【问题标题】:Angular. Watching a service for changes?角。关注服务的变化?
【发布时间】:2015-01-04 21:51:00
【问题描述】:

您有一个名为“DataService”的服务,其中包含一个闭包。
闭包属性可以通过get/set/display(ClosurePropertyName)获取/设置/显示:

var app = angular.module('app',[]);
    app.service('DataService', [function(){
      var data = this;
    (function initialize() {
    var closure = {
        prop: 'etc',
        otherProp: [],
        diffProp: {
            a: 'b',
            c: 'd'
        }
    }, keys = Object.keys(closure);

    // ex: data.displayProp() 
    // returns : Displaying etc
    data.displayProp = function () {
        return 'Displaying: ' + closure.prop;
    }


    // ex: data.getProp() 
    // returns : etc
    data.getProp = function () {
        return closure.prop;
    }
    // ex: data.setProp("derp");
    // becomes: closure.prop = "derp"
    data.setProp = function (val) {
        closure.prop = val;
    }
    data.allProps = function () {
        var obj = {};
        for (var i = 0; i < keys.length; i++) {
            obj[keys[i]] = closure[keys[i]];
        }
        return obj;
    }
    })();
}]);

您有访问此服务的控制器:

  app.controller('CntrlA', ['$scope', 'DataService', function($scope, DataService){  
     var props = DataService.allProps();
     this.props = props;
     this.changeProp = function(val){
       DataService.setProp(val);
     }

     $scope.CntrlA = this;
     return $scope.CntrlA;
   }]);

   app.controller('CntrlB',  ['$scope', 'DataService', function($scope, DataService){
     var props = DataService.allProps();
      this.changeOtherProps = function(arr){
        DataService.setOtherProp(arr);
     }
     $scope.CntrlB = this;
     return $scope.CntrlB
   }]); 

还有简单的html:

body[ng-app="app"]

  div[ng-controller="CntrlA as aa"]
    button[ng-click="aa.changeProp('herp a derp')"]
    div "{{aa.props}}"

  div[ng-controller="CntrlB as bb"]
    button[ng-click="bb.setOtherProp(['all', 'the', 'things'])"]
    div "{{bb.props}}"

当值发生变化时,如何将更改应用于两者?我知道这必须很简单,但是 $scope.$watch 不起作用。

【问题讨论】:

    标签: angularjs data-binding binding


    【解决方案1】:

    在这种情况下,使用 $watch 看起来像这样:

    $scope.$watch(function() {
        return DataService.allProps();
      },
      function(newValue, oldValue) {
        if (newValue === oldValue) return;
        $scope.CntrlA.props = newValue;
      }, true);
    

    由于allProps 每次都会返回一个新的对象引用,所以您需要将true 作为第三个参数传递。否则你会得到“Infinite $digest Loop”错误。

    但是,在这种情况下使用$watch 根本没有效率。每个摘要循环包含多个摘要循环,每个循环将执行DataService.allProps() 和其中的迭代。而且由于您必须将true 作为第三个参数传递给$watch,它将在内部使用angular.equalsangular.copy,这涉及到更昂贵的操作。

    使用$watch 演示(检查控制台): http://plnkr.co/edit/DLmT5XAPBXA3dg5DENRS?p=preview

    如果您的服务需要看起来像这样,更好的解决方案是在每次属性更改时触发一个事件。这样消化周期就不会负担。

    例如:

    data.setProp = function(val) {
      closure.prop = val;
      $rootScope.$emit('DataService:update');
    };
    

    在控制器中:

    var unregister = $rootScope.$on('DataService:update', function() {
      $scope.CntrlA.props = DataService.allProps();
    });
    
    $scope.$on('$destroy', unregister);
    

    $emit 演示: http://plnkr.co/edit/QfdqGsLVXYnL4HIy82gk?p=preview

    【讨论】:

    • 不错。谢谢,伙计:-)你说'如果你的服务需要看起来像这样'......我实际上一直在试图弄清楚我是否使用最好的角度元素类型来处理这种事情 - 你有没有机会可以谈谈您将如何构建服务吗?你还会让它成为一项服务吗?
    猜你喜欢
    • 2015-04-05
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 2019-10-13
    相关资源
    最近更新 更多