Angular $ scope $ watch on service function return value

时间:2015-11-03 09:56:41

标签: javascript angularjs

我的websocket连接有一个服务,这个服务在函数中返回客户端是否实际连接的实际状态。 我简化了我的代码,这些代码片段是我的问题的一个小例子:

myApp.factory('Websocket', function() {
    //the status boolean whether connected or not
    var bool = true;

    //small mock for the status change
    setInterval(function() {
        bool = !bool;
    }, 1000);

    //i've made the value of the status variable accessable in a function or the variable itself
    return {
        status: function() {
            return bool;   
        },
        var: bool
    }
});

现在我尝试将状态值应用于控制器中的范围:

myApp.controller('Ctrl', function(Websocket, $scope) {
   //method 1
   $scope.status = Websocket.status();

   //method 2
   $scope.$watch(function() {
     return Websocket.status();
   }, function(newVal) {
     $scope.status = newVal;
   });
});

...但是这两种方法都不起作用,也没有为这个html更新$ scope变量:

<div ng-app="myApp">
    <div ng-controller="Ctrl">
      method1: {{status}}
    </div>
</div>

这是一个codepen:http://codepen.io/anon/pen/bVjaBa?editors=101

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

问题出在Nikos上面提到:你正在改变摘要循环之外的变量值,所以angular不跟随变化。

使用$scope.$apply是一种选择,但在这种情况下,我更倾向于使用$interval而不是setInterval

myApp.factory('Websocket', function($interval) {
  var bool = true;
  $interval(function() {
    bool = !bool;
  }, 1000);

  return {
    status: function() {
        return bool;   
    },
    var: bool
  }
});

看到它正常工作here

答案 1 :(得分:1)

问题在于,对Angular监视的数据进行的任何“外部”更改都必须调用scope.$apply()以供观察者更新(此处观察者是来自{{status}}表达式的UI)。在codepen中,解决方案很简单:使服务依赖于$rootScope并在区间函数中调用$rootScope.$apply()

myApp.factory('Websocket', function($rootScope) {
    ...
    setInterval(function() {
        bool = !bool;
        $rootScope.$apply();
    }, 1000);
    ...
});

必须对真实服务做类似的事情,关键概念是:(1)你必须调用$apply()和(2)无法访问特定范围,只需使用$rootScope