0

在我的应用程序中,我想要一个自我更新的数据服务,它被注入到控制器中:

app.factory("StatsService", function() {
    var service;
    service = {
        data: 0,
        init: function() {
            var self = this;
            setInterval(function() {
                self.data = Math.floor((Math.random() * 100) + 1);
            }, 1000);
        }
    };
    service.init();
    return service;
});

这是一个示例控制器:

app.controller("SourcesController", ['$scope', 'StatsService', function($scope, StatsService) {
    $scope.data = StatsService.data;

    $scope.$watch('data', function(val) {
        // this does not work either
    });
}

如何让控制器反映服务更改?我不知道我是否在服务或控制器方面做错了,它只是不起作用。

4

3 回答 3

2

由于 data 属性是一个原始的int,值被复制到你scope.data。现在这些是两个单独的值,一个存储在服务中,一个存储在控制器中。因此,即使服务数据发生变化,也不会影响控制器数据属性。

为了使它们保持同步,请使用具有子属性的对象。因此,服务中的数据声明变为

data:{value:0}

并且无论你在哪里绑定使用表达式data.value

于 2013-08-21T12:17:39.937 回答
1

您的代码的问题setInterval()是发生在 Angular 世界之外。如果你在 Angular 世界之外修改东西,那么框架不知道变化。在这种情况下,您需要将代码包装到$apply调用中以通知框架。

app.factory("StatsService", ['$rootScope', function($rootScope) {
    var service;
    service = {
        data: 0,
        init: function() {
            var self = this;
            setInterval(function() {
                $rootScope.$apply(function(){
                    self.data = Math.floor((Math.random() * 100) + 1);
                });
            }, 1000);
        }
    };
    service.init();
    return service;
}]);

通常你不需要担心这一点,因为 Angular 挂钩了大多数可能导致状态改变的事情。例如,如果您使用setTimeout而不是setInterval您可以使用 Angular 的$timeout服务,该服务会在幕后通知框架,这样您就不必这样做了。在 JavaScript 中无论如何使用setTimeoutfor是一个好主意,因为 的调用可能是不确定的。setIntervalsetInterval

我不想深入探讨该主题,但如果您对为什么偏爱感兴趣,setTimeoutsetInterval推荐 John Resig 关于该主题的帖子:

http://ejohn.org/blog/how-javascript-timers-work/

我也不想深入了解 Angular 的数据绑定如何工作的细节,因为在 SO 上已经有关于该主题的一些很好的答案:

链接:

AngularJS 中的数据绑定是如何工作的?

于 2013-08-21T12:59:17.893 回答
0

Chandermani 的分析是正确的。除了更改服务之外,另一种选择是将控制器更改为具有返回值的函数。例如`

app.controller("SourcesController", ['$scope', 'StatsService', function($scope, StatsService) {
  $scope.data = function(newValue) {
    if(arguments.length === 0) return StatsService.data;
    StatsService.data = newValue;
  }

  $scope.$watch('data()', function(val) {
  });
}

不便之处在于您必须data()在绑定中使用才能访问该值并data(value)对其进行更改。

于 2013-08-21T12:31:29.033 回答