注入控制器的自更新服务

时间:2013-08-21 12:00:30

标签: javascript angularjs angularjs-scope

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

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

如何让控制器反映服务变更?我不知道我是否对服务或控制器做错了什么,它只是不起作用。

3 个答案:

答案 0 :(得分:2)

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

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

data:{value:0}

在哪里绑定使用表达式data.value

答案 1 :(得分: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中使用setTimeout支持setInterval实际上是一个好主意,因为setInterval的调用可能是非确定性的。

我不想深入探讨该主题,但如果您对为setTimeout而不是setInterval感兴趣,我建议John Resig就该主题发表文章:

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

我也不想深入了解Angular的数据绑定的工作原理,因为在SO上已经有一些很好的答案:

<强>链接:

How does data binding work in AngularJS?

答案 2 :(得分: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)来更改它。