【问题标题】:Watch multiple $scope attributes查看多个 $scope 属性
【发布时间】:2012-08-10 18:16:01
【问题描述】:

有没有办法使用$watch订阅多个对象上的事件

例如

$scope.$watch('item1, item2', function () { });

【问题讨论】:

    标签: javascript angularjs events angularjs-watch


    【解决方案1】:

    从 AngularJS 1.3 开始,有一个名为 $watchGroup 的新方法用于观察一组表达式。

    $scope.foo = 'foo';
    $scope.bar = 'bar';
    
    $scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
      // newValues array contains the current values of the watch expressions
      // with the indexes matching those of the watchExpression array
      // i.e.
      // newValues[0] -> $scope.foo 
      // and 
      // newValues[1] -> $scope.bar 
    });
    

    【讨论】:

    • 与 $watchCollection('[a, b]') 有什么区别??
    • 不同之处在于可以使用合适的数组代替看起来像数组的字符串
    • 我遇到了类似的问题,但使用的是 controllerAs 模式。在我的情况下,修复包括在变量前面加上控制器的名称:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
    • 这在 Angular 1.6 上似乎对我不起作用。如果我在函数上添加控制台日志,我可以看到它只运行一次,newValuesoldValuesundefined,同时单独观察属性正常工作。
    【解决方案2】:

    从 AngularJS 1.1.4 开始你可以使用$watchCollection:

    $scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
        // do stuff here
        // newValues and oldValues contain the new and respectively old value
        // of the observed collection array
    });
    

    Plunker 示例here

    文档here

    【讨论】:

    • 请注意,第一个参数不是数组。这是一个看起来像数组的字符串。
    • 感谢您。如果对我有用,我会给你一千金币——当然是虚拟金币 :)
    • 要清楚(我花了几分钟才意识到)$watchCollection 旨在被交给一个对象并提供对任何对象属性更改的监视,而 $watchGroup 旨在被交给一组单独的属性来观察变化。解决相似但不同的问题略有不同。呸!
    • 不知何故,当您使用此方法时,newValues 和 oldValues 总是相等的:plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
    • 谢谢。它解决了我的问题。使用 $watch 是否有任何性能损失/问题?
    【解决方案3】:

    $watch第一个参数也可以是函数。

    $scope.$watch(function watchBothItems() {
      return itemsCombinedValue();
    }, function whenItemsChange() {
      //stuff
    });
    

    如果您的两个组合值很简单,则第一个参数通常只是一个角度表达式。例如,名字和姓氏:

    $scope.$watch('firstName + lastName', function() {
      //stuff
    });
    

    【讨论】:

    • 这似乎是一个要求默认包含在框架中的用例。即使像fullName = firstName + " " + lastName 这样简单的计算属性也需要传递一个函数作为第一个参数(而不是像'firstName, lastName' 这样的简单表达式)。 Angular 非常强大,但在某些领域,它可以以不(似乎)损害性能或设计原则的方式对开发人员更加友好。
    • 那么 $watch 只是接受一个角度表达式,它在它被调用的范围内进行评估。所以你可以做$scope.$watch('firstName + lastName', function() {...})。你也可以只做两块手表:function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);。我在答案中添加了简单的案例。
    • 'firstName + lastName' 中的加号是字符串连接。所以 Angular 现在只是检查连接的结果是否不同。
    • 字符串连接需要一点小心——如果将“paran orman”更改为“para norman”,则不会触发响应;最好在第一个术语和第二个术语之间放置一个分隔符,例如“\t|\t”,或者只使用明确的 JSON
    • 虽然 amberjs 很烂,但它内置了这个功能!听到那些有棱角的家伙。我觉得做手表是最合理可行的方式。
    【解决方案4】:

    这是一个非常类似于您的实际工作的原始伪代码的解决方案:

    $scope.$watch('[item1, item2] | json', function () { });
    

    编辑:好的,我认为这更好:

    $scope.$watch('[item1, item2]', function () { }, true);
    

    基本上我们跳过了 json 步骤,一开始这似乎很愚蠢,但没有它就无法工作。它们的关键是经常省略的第三个参数,它打开对象相等而不是引用相等。然后我们创建的数组对象之间的比较实际上是正确的。

    【讨论】:

    • 我也有类似的问题。这对我来说是正确的答案。
    • 如果数组表达式中的项目不是简单类型,两者都会有轻微的性能开销。
    • 确实如此。它正在对组件对象进行全深度比较。这可能是也可能不是你想要的。请参阅当前批准的使用现代角度的版本的答案,该版本不进行完整的深度比较。
    • 由于某种原因,当我尝试在数组上使用 $watchCollection 时,我收到了这个错误 TypeError: Object #<Object> has no method '$watchCollection' 但这个解决方案可以帮助我解决我的问题!
    • 酷,你甚至可以观察对象内的值:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
    【解决方案5】:

    您可以使用 $watchGroup 中的函数来选择范围内对象的字段。

            $scope.$watchGroup(
            [function () { return _this.$scope.ViewModel.Monitor1Scale; },   
             function () { return _this.$scope.ViewModel.Monitor2Scale; }],  
             function (newVal, oldVal, scope) 
             {
                 if (newVal != oldVal) {
                     _this.updateMonitorScales();
                 }
             });
    

    【讨论】:

    • 你为什么使用_this?在没有明确定义的情况下,范围不会被带到函数中吗?
    • 我用打字稿,呈现的代码是编译结果。
    【解决方案6】:

    为什么不简单地将其包装在 forEach 中?

    angular.forEach(['a', 'b', 'c'], function (key) {
      scope.$watch(key, function (v) {
        changed();
      });
    });
    

    这与为组合值提供函数的开销大致相同,实际上不必担心值的构成

    【讨论】:

    • 在这种情况下 log() 会被执行多次,对吧?我认为在嵌套 $watch 函数的情况下它不会。而且它不应该出现在同时查看多个属性的解决方案中。
    • 不,每个监视属性的每次更改仅执行一次日志。为什么会被多次调用?
    • 对,我的意思是,如果我们想同时观看所有这些,那效果就不太好了。
    • 当然,为什么不呢?我在我的一个项目中就是这样做的。 changed() 在任一属性发生变化时被调用。这与提供组合值的函数完全相同。
    • 略有不同的是,如果数组中的多个项目同时更改,$watch 只会触发一次处理程序,而不是每个更改的项目一次。
    【解决方案7】:

    一个更安全的组合值的解决方案可能是使用以下作为您的 $watch 函数:

    function() { return angular.toJson([item1, item2]) }
    

    $scope.$watch(
      function() {
        return angular.toJson([item1, item2]);
      },
      function() {
        // Stuff to do after either value changes
      });
    

    【讨论】:

      【解决方案8】:

      $watch 第一个参数可以是angular expression 或函数。请参阅$scope.$watch 上的文档。它包含很多关于 $watch 方法如何工作的有用信息:何时调用 watchExpression,角度如何比较结果等。

      【讨论】:

        【解决方案9】:

        怎么样:

        scope.$watch(function() { 
           return { 
              a: thing-one, 
              b: thing-two, 
              c: red-fish, 
              d: blue-fish 
           }; 
        }, listener...);
        

        【讨论】:

        • 我发现这个解决方案适合我的情况。对我来说,它更像是:return { a: functionA(), b: functionB(), ... }。然后,我将新值和旧值的返回对象相互检查。
        【解决方案10】:
        $scope.$watch('age + name', function () {
          //called when name or age changed
        });
        

        当年龄和姓名值都改变时,这里的函数将被调用。

        【讨论】:

        • 还要确保在这种情况下不要使用 angular 传递给回调的 newValue 和 oldValue 参数,因为它们将是结果连接,而不仅仅是更改的字段
        【解决方案11】:

        Angular 在 1.3 版中引入了$watchGroup,我们可以使用它来观察多个变量,只需一个$watchGroup$watchGroup 将数组作为第一个参数,我们可以在其中包含所有要观察的变量。

        $scope.$watchGroup(['var1','var2'],function(newVals,oldVals){
           console.log("new value of var1 = " newVals[0]);
           console.log("new value of var2 = " newVals[1]);
           console.log("old value of var1 = " oldVals[0]);
           console.log("old value of var2 = " oldVals[1]);
        });
        

        【讨论】:

          猜你喜欢
          • 2019-04-20
          • 2015-09-17
          • 2018-06-19
          • 1970-01-01
          • 2021-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多