我很难理解这里发生了什么。我了解Angular的$digest循环的基本原理,根据这篇SO文章,我只需将一个作用域var分配给服务的属性(在本例中是一个数组),就可以正确地完成任务。正如您所看到的,我可以更新CtrlA的"things"的唯一方法是在我用对新数组的引用更新了服务的属性后重新分配它。
这是一把小提琴,它说明了我的问题:
http://jsfiddle.net/tehsuck/Mujun/
(function () {
angular.module('testApp', [])
.factory('TestService', function ($http) {
var service = {
things: [],
setThings: function (newThings) {
service.things = newThings;
}
};
return service;
})
.controller('CtrlA', function ($scope, $timeout, TestService) {
$scope.things = TestService.things;
$scope.$watch('things.length', function (n, o) {
if (n !== o) {
alert('Things have changed in CtrlA');
}
});
$timeout(function () {
TestService.setThings(['a', 'b', 'c']);
// Without the next line, CtrlA acts like CtrlB in that
// it's $scope.things doesn't receive an update
$scope.things = TestService.things;
}, 2000);
})
.controller('CtrlB', function ($scope, TestService) {
$scope.things = TestService.things;
$scope.$watch('things.length', function (n, o) {
if (n !== o) {
// never alerts
alert('Things have changed in CtrlB');
}
});
})
})();
您的代码有两个问题:
-
数组没有
count
属性;您应该使用length
。$scope.$watch('things.length', ...);
但有一点需要注意:如果在
things
数组中添加和删除元素,最终得到一个长度相同的不同列表,则不会触发观察者回调。 -
TestService
的setThings
方法将对things
阵列的引用替换为新的引用,使TestService.things
指向内存中的新阵列,而CtrlA.$scope.things
和CtrlB.$scope.things
都保持指向空的旧阵列。以下代码说明:var a = []; var b = a; a = [1, 2, 3]; console.log(a); // prints [1, 2, 3]; console.log(b); // prints [];
因此,为了让代码正常工作,您需要更改
TestService.setThings
更新其things
数组的方式。这里有一个建议:setThings: function (newThings) { service.things.length = 0; // empties the array newThings.forEach(function(thing) { service.things.push(thing); });
}
这是您的jsFiddle的工作版本。
我真的不知道为什么,但如果你使用一个函数来返回服务中的数据,然后你观察该函数而不是属性,这似乎是正确的。由于似乎不清楚,您可以在此处看到:http://jsfiddle.net/DotDotDot/Mujun/10/
我在您的服务中添加了一个getter:
var service = {
things: [],
setThings: function (newThings) {
service.things = newThings;
},
getThings:function(){
return service.things;
}
};
然后,我修改了你在两个控制器中的代码:
$scope.things = TestService.getThings();
$scope.getThings=function(){return TestService.getThings();};
$scope.$watch('getThings()', function (n, o) {
if (n !== o) {
// never alerts
alert('Things have changed in CtrlA');
}
}, true);
以及在HTML:中
<li ng-repeat="thing in getThings()">{{thing}}</li>
它定义了一个函数getThings,它只需获取服务中的属性,然后我观察这个函数(AFAIK$watch对参数进行评估,这样你就可以观察函数),并进行深度检查(最后是真正的参数)。你的另一个控制器也是一样。然后,当您修改服务的值时,两个$watcher会看到它,并且数据被正确地绑定到
事实上,我不知道这是否是最好的方法,但它似乎适用于你的例子,所以我认为你可以这样看
玩得开心:)