解释的最佳方式是这个例子:
<table ng-controller="groupOfPeopleController">
<tr ng-repeat "person in peoples">
<td>{{person.name}}</td>
<td><button ng-click="load_data(person.id)">Load Data</button>
<td><div class="personData" ng-controller="personDataController"></div></td>
</tr>
</table>
我要做的是用它自己的数据填充div.personData。所以我在groupOfPeopleController中有一个名为load_data(id)的函数:
// groupOfPeopleController
$scope.load_data = function(id){
$rootScope.$broadcast('load_data'id);
}
我想专门传递给子元素控制器personData。
// personDataController
$scope.$on('load_data',function(e,id){
// hopefully affect only the div inside the current loop...
});
问题是,它附加到personData的每个循环。因此,单击一个人会影响每一行,因为它们都连接到同一个控制器。
我如何制作personData的单独实例?广播的方式是错误的吗?
答案 0 :(得分:1)
请勿使用广播。是的,事件是好的,但在这种情况下不是。 并且循环中的项目正在更新,因为循环中的每个项都接收对同一个控制器的引用而不是它的实例。
正确的做法是使用指令。
将模板更改为:
<tr ng-repeat="person in peoples" data-person="person"></tr>
并使用类似这样的指令:
app.directive('person', function(){
var templateStr = '<td>{{person.name}}</td>' +
'<td><button ng-click="load_data(person.id)">Load Data</button>' +
'<td><div class="personData">{{person.anyDataYouWantToDisplay}}</div></td>';
var linkFn = function(scope){
scope.load_data = function(id){
// load person data and do something about it
};
// do other magic here as it is the controller for your individual person
};
return {
restrict: 'A',
scope: {
person: '='
}
link: linkFn,
template: templateStr
};
});
希望有所帮助。
答案 1 :(得分:1)
不要从$ rootScope广播,它会将事件名称向下调度到所有子范围(及其子项递归)。
你能做什么,只是来自当前范围,而不是所有范围。请参阅此plunker。
主要技巧是您需要子范围ng-repeat创建,因此您将关键字“this”传递给获取当前范围的函数,然后从那里广播事件。
元素:
<button ng-click="load_data(this, person.id)">Load Data</button>
groupOfPeopleController:
$scope.load_data = function(childScope, id){
childScope.$broadcast('load_data', id);
}
但是,我建议不要使用此方法。为什么要播放任何广播/ $ on?您可以简单地将personDataController移动到tr的整个内容,并直接从ng-click调用loadData函数,如this plunker中所示。它可以为您节省一些麻烦和烦恼。