AngularJS:如何看服务变量?

我有一个服务,说:

factory('aService', ['$rootScope', '$resource', function ($rootScope, $resource) {
  var service = {
    foo: []
  };

  return service;
}]);

我想用foo来控制以HTML格式呈现的列表:

<div ng-controller="FooCtrl">
  <div ng-repeat="item in foo">{{ item }}</div>
</div>

为了让控制器能够检测到aService.foo更新的时间,我已经将这个模式拼凑在了一起,并在控制器的$scope添加aService,然后使用$scope.$watch()

function FooCtrl($scope, aService) {                                                                                                                              
  $scope.aService = aService;
  $scope.foo = aService.foo;

  $scope.$watch('aService.foo', function (newVal, oldVal, scope) {
    if(newVal) { 
      scope.foo = newVal;
    }
  });
}

这感觉是长期的,我一直在使用服务变量的每个控制器中重复它。 有没有更好的方法来完成观看共享变量?


如果你想避免$watch的暴政和开销,你总是可以使用好的旧观察者模式。

在服务中:

factory('aService', function() {
  var observerCallbacks = [];

  //register an observer
  this.registerObserverCallback = function(callback){
    observerCallbacks.push(callback);
  };

  //call this when you know 'foo' has been changed
  var notifyObservers = function(){
    angular.forEach(observerCallbacks, function(callback){
      callback();
    });
  };

  //example of when you may want to notify observers
  this.foo = someNgResource.query().$then(function(){
    notifyObservers();
  });
});

在控制器中:

function FooCtrl($scope, aService){
  var updateFoo = function(){
    $scope.foo = aService.foo;
  };

  aService.registerObserverCallback(updateFoo);
  //service now in control of updating foo
};

在这种情况下,多个/未知对象可能对更改感兴趣,请使用正在更改的项目中的$rootScope.$broadcast

与其创建自己的监听器注册表(必须在各种$破坏条件下清理),您应该能够从相关服务中进行$broadcast

您仍然必须在每个侦听器$on编写$on处理程序,但该模式与多次调用分离为$digest ,从而避免了长时间运行的监视器的风险。

通过这种方式,监听器也可以来自DOM和/或不同的子范围,而不会改变服务的行为。

**更新:示例**

广播可能会影响“全球”服务,这可能会影响您的应用中无数其他事物。 一个很好的例子是一个用户服务,其中有许多事件可以发生,例如登录,注销,更新,空闲等。我认为这是广播最有意义的地方,因为任何范围都可以监听事件,而无需甚至注入服务,并且它不需要评估任何表达式或缓存结果来检查更改。 它只是开火和忘记(所以要确保它是一个即发即忘通知,而不是需要采取行动的事情)

.factory('UserService', [ '$rootScope', function($rootScope) {
   var service = <whatever you do for the object>

   service.save = function(data) {
     .. validate data and update model ..
     // notify listeners and provide the data that changed [optional]
     $rootScope.$broadcast('user:updated',data);
   }

   // alternatively, create a callback function and $broadcast from there if making an ajax call

   return service;
}]);

当save()函数完成且数据有效时,上述服务将向每个范围广播一条消息。 或者,如果它是$资源或ajax提交,请将广播呼叫转移到回调中,以便在服务器响应时触发。 广播很适合这种模式,因为每个听众只是等待事件而不需要检查每个消息的范围。 听众会看起来像:

.controller('UserCtrl', [ 'UserService', '$scope', function(UserService, $scope) {

  var user = UserService.getUser();

  // if you don't want to expose the actual object in your scope you could expose just the values, or derive a value for your purposes
   $scope.name = user.firstname + ' ' +user.lastname;

   $scope.$on('user:updated', function(event,data) {
     // you could inspect the data to see if what you care about changed, or just update your own scope
     $scope.name = user.firstname + ' ' + user.lastname;
   });

   // different event names let you group your code and logic by what happened
   $scope.$on('user:logout', function(event,data) {
     .. do something differently entirely ..
   });

 }]);

其中一个好处是消除了多个手表。 如果你要合并字段或者像上面的例子那样得到值,你必须同时观察名字和姓氏属性。 只有用户对象在更新时被替换,才能使用getUser()函数,如果用户对象仅更新其属性,则不会触发。 在这种情况下,你必须进行深入观察,这是更密集的。

$ broadcast将消息从调用的范围发送到任何子范围。 所以从$ rootScope调用它将在每个范围上触发。 例如,如果您要从控制器的作用域进行广播,则只会在继承自控制器作用域的作用域中触发。 $ emit的方向相反,其行为与DOM事件类似,因为它会激发范围链。

请记住,有些情况下$广播很有意义,有些情况下$ watch是更好的选择 - 尤其是在具有非常特定的观看表达式的隔离范围内时。


我使用类似的方法作为@dtheodot,但使用角度承诺而不是传递回调

app.service('myService', function($q) {
    var self = this,
        defer = $q.defer();

    this.foo = 0;

    this.observeFoo = function() {
        return defer.promise;
    }

    this.setFoo = function(foo) {
        self.foo = foo;
        defer.notify(self.foo);
    }
})

然后,只要使用myService.setFoo(foo)方法来更新服务上的foo 。 在你的控制器中,你可以使用它:

myService.observeFoo().then(null, null, function(foo){
    $scope.foo = foo;
})

then前两个参数是成功和错误回调,第三个是通知回调。

参考$ q。

链接地址: http://www.djcxy.com/p/77851.html

上一篇: AngularJS : How to watch service variables?

下一篇: router WARNING: Tried to load angular more than once