2

I am having a really hard time deciphering what is going on here. I understand the basics of Angular's $digest cycle, and according to this SO post, I am doing things correctly by simply assigning a scoped var to a service's property (an array in this case). As you can see the only way I can get CtrlA's 'things' to update is by re-assigning it after I've updated my service's property with a reference to a new array.

Here is a fiddle which illustrates my issue:

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');
        }
    });
})

})();

4

2 回答 2

4

您的代码有两个问题:

  1. 数组没有count属性;你应该length改用。

    $scope.$watch('things.length', ...);
    

    但是有一个警告:如果您在数组中添加和删除元素things并最终得到具有相同长度的不同列表,则不会触发观察者回调。

  2. setThings方法用一个新的TestService替换对数组的引用,指向内存中的一个新数组,同时保持指向旧数组,它是空的。以下代码说明了这一点:thingsTestService.thingsCtrlA.$scope.thingsCtrlB.$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 的工作版本

于 2013-08-18T17:07:35.933 回答
1

我真的不知道为什么,但是如果您使用函数返回服务中的数据,然后您观察该函数而不是属性,它似乎会得到纠正。似乎不清楚,您可以在这里看到:http: //jsfiddle.net/DotDotDot/Mujun/10/
我在您的服务中添加了一个吸气剂:

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 对参数进行 eval,所以你可以观察函数),并进行深入检查(最后的 true 参数)。在您的另一个控制器中也是如此。然后,当你修改你的服务的值时,它被两个 $watchers 看到,并且数据被正确绑定

实际上,我不知道这是否是最好的方法,但它似乎适用于您的示例,所以我认为您可以这样看

玩得开心 :)

于 2013-08-18T15:37:03.800 回答