AngularJS:如何观察服务变量?

本文翻译自:AngularJS : How to watch service variables?

I have a service, say: 我有服务,说:

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

  return service;
}]);

And I would like to use foo to control a list that is rendered in HTML: 我想使用foo来控制以HTML格式呈现的列表:

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

In order for the controller to detect when aService.foo is updated I have cobbled together this pattern where I add aService to the controller's $scope and then use $scope.$watch() : 为了让控制器检测aService.foo更新,我将这个模式拼凑在一起,我将aService添加到控制器的$scope ,然后使用$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;
    }
  });
}

This feels long-handed, and I've been repeating it in every controller that uses the service's variables. 这感觉很长,我一直在每个使用服务变量的控制器中重复它。 Is there a better way to accomplish watching shared variables? 有没有更好的方法来完成观察共享变量?


#1楼

参考:https://stackoom.com/question/qlna/AngularJS-如何观察服务变量


#2楼

As far as I can tell, you dont have to do something as elaborate as that. 据我所知,你不必做那样详细的事情。 You have already assigned foo from the service to your scope and since foo is an array ( and in turn an object it is assigned by reference! ). 您已经将foo从服务分配给范围,因为foo是一个数组(反过来它是一个通过引用分配的对象!)。 So, all that you need to do is something like this : 所以,你需要做的就是这样:

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

 }

If some, other variable in this same Ctrl is dependant on foo changing then yes, you would need a watch to observe foo and make changes to that variable. 如果有的话,同一个Ctrl中的其他变量依赖于foo更改然后是,你需要一个手表来观察foo并对该变量进行更改。 But as long as it is a simple reference watching is unnecessary. 但只要它是一个简单的参考,观看是不必要的。 Hope this helps. 希望这可以帮助。


#3楼

A wee bit ugly, but I've added registration of scope variables to my service for a toggle: 有点难看,但我已经将范围变量的注册添加到我的服务中以进行切换:

myApp.service('myService', function() {
    var self = this;
    self.value = false;
    self.c2 = function(){};
    self.callback = function(){
        self.value = !self.value; 
       self.c2();
    };

    self.on = function(){
        return self.value;
    };

    self.register = function(obj, key){ 
        self.c2 = function(){
            obj[key] = self.value; 
            obj.$apply();
        } 
    };

    return this;
});

And then in the controller: 然后在控制器中:

function MyCtrl($scope, myService) {
    $scope.name = 'Superhero';
    $scope.myVar = false;
    myService.register($scope, 'myVar');
}

#4楼

You can always use the good old observer pattern if you want to avoid the tyranny and overhead of $watch . 如果你想避免$watch的暴政和开销,你总是可以使用好的旧观察者模式。

In the service: 在服务中:

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

And in the controller: 在控制器中:

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

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

#5楼

Building on dtheodor's answer you could use something similar to the below to ensure that you don't forget to unregister the callback... Some may object to passing the $scope to a service though. 基于dtheodor的答案,您可以使用类似于下面的内容来确保您不会忘记取消注册回调...有些人可能会反对将$scope传递给服务。

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

  /**
   * Registers a function that will be called when
   * any modifications are made.
   *
   * For convenience the callback is called immediately after registering
   * which can be prevented with `preventImmediate` param.
   *
   * Will also automatically unregister the callback upon scope destory.
   */
  this.registerObserver = function($scope, cb, preventImmediate){
    observerCallbacks.push(cb);

    if (preventImmediate !== true) {
      cb();
    }

    $scope.$on('$destroy', function () {
      observerCallbacks.remove(cb);
    });
  };

  function notifyObservers() {
    observerCallbacks.forEach(function (cb) {
      cb();
    });
  };

  this.foo = someNgResource.query().$then(function(){
    notifyObservers();
  });
});

Array.remove is an extension method which looks like this: Array.remove是一个扩展方法,如下所示:

/**
 * Removes the given item the current array.
 *
 * @param  {Object}  item   The item to remove.
 * @return {Boolean}        True if the item is removed.
 */
Array.prototype.remove = function (item /*, thisp */) {
    var idx = this.indexOf(item);

    if (idx > -1) {
        this.splice(idx, 1);

        return true;
    }
    return false;
};

#6楼

Here's my generic approach. 这是我的通用方法。

mainApp.service('aService',[function(){
        var self = this;
        var callbacks = {};

        this.foo = '';

        this.watch = function(variable, callback) {
            if (typeof(self[variable]) !== 'undefined') {
                if (!callbacks[variable]) {
                    callbacks[variable] = [];
                }
                callbacks[variable].push(callback);
            }
        }

        this.notifyWatchersOn = function(variable) {
            if (!self[variable]) return;
            if (!callbacks[variable]) return;

            angular.forEach(callbacks[variable], function(callback, key){
                callback(self[variable]);
            });
        }

        this.changeFoo = function(newValue) {
            self.foo = newValue;
            self.notifyWatchersOn('foo');
        }

    }]);

In Your Controller 在您的控制器中

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

    $scope._initWatchers = function() {
        aService.watch('foo', $scope._onFooChange);
    }

    $scope._onFooChange = function(newValue) {
        $scope.foo = newValue;
    }

    $scope._initWatchers();

}

FooCtrl.$inject = ['$scope', 'aService'];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值