【问题标题】:Why is $watch not firing even with objectEquality set to true?为什么即使 objectEquality 设置为 true,$watch 也不会触发?
【发布时间】:2015-03-04 08:48:27
【问题描述】:

在下面的代码中,$watch 应该在变量scores 发生变化时执行函数recalculateInfoBox。但是,它什么也没做。

我已经阅读了将true 添加为 $watch 的第三个变量通常可以解决问题,但在这种情况下 $watch 仍然不会触发。

我还需要进行哪些更改才能触发 $watch?

<html ng-app="mainModule">
    <head>
        <style type="text/css">
        </style>
    </head>    
    <body ng-controller="mainController" >

        <div>Scores: <input type="text" ng-model="scores" ng-list style="width:500px" placeholder="Enter comma-separated list..."/></div>
        <div>You have {{scores.length}} items.</div>
        <hr/>
        ng-style:
        <div ng-style="{'width': infoBox.width, 'background-color': infoBox.backgroundColor}">
            This is the info.
        </div>
        <button ng-click="infoBox.width = '300px'">small</button> 
        <button ng-click="infoBox.width = '800px'">large</button> 
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
        <script>
                    var mainModule = angular.module('mainModule', []);
                            function mainController($scope) {
                                $scope.scores = [];
                                $scope.infoBox = {width: '300px', backgroundColor: '#ddd'};
                                var recalculateInfoBox = function () {
                                    console.log('in recalc');
                                    $scope.infoBox.width = '100px';
                                };
                                $scope.$watch('scores', 'recalculateInfoBox', true);
                            }
        </script>
    </body>
</html>

【问题讨论】:

  • 另外,使用 ng-list 时不需要对象相等性

标签: angularjs watch


【解决方案1】:

$scope.$watch 采用回调函数(不是回调函数的名称)。

所以,改成这个应该可以:

var recalculateInfoBox = function () {
    console.log('in recalc');
    $scope.infoBox.width = '100px';
};
$scope.$watch('scores', recalculateInfoBox, true);

来自the docs

$watch(watchExpression, listener, [objectEquality]);

注册一个 listener 回调以在任何时候执行 watchExpression 发生变化。

【讨论】:

  • 完美,我的疏忽,现在有效,我猜它与这种语法混淆了,myAppModule.controller('TextController',...
  • 这可能有点令人困惑:)。例如,$watch 的第一个参数可以是 $scope 属性 name 或 JavaScript 表达式(回调),返回检查更改的值。跨度>
【解决方案2】:

问题不是因为对象相等,而是因为listener 必须是函数引用而不是函数名称。与第一个参数(通常作为字符串提供)的作用域属性评估不同,Angular 甚至不会从作用域评估函数(即使您将方法添加为作用域对象的属性)。

$scope.$watch('scores', 'recalculateInfoBox', true);

应该是

$scope.$watch('scores', recalculateInfoBox, true);

angular.module('app', []).controller('ctrl', function($scope) {
  $scope.scores = [];
  $scope.infoBox = {
    width: '300px',
    backgroundColor: '#ddd'
  };
  var recalculateInfoBox = function() {
    console.log(arguments);
    $scope.infoBox.width = '100px';
  };
  $scope.$watch('scores', recalculateInfoBox);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <div>Scores:
    <input type="text" ng-paste="handlePaste($event)" ng-model="scores" ng-list style="width:500px" placeholder="Enter comma-separated list..." />
  </div>
  <div>You have {{scores.length}} items.</div>
  <hr/>ng-style:
  <div ng-style="{'width': infoBox.width, 'background-color': infoBox.backgroundColor}">
    This is the info.
  </div>
  <button ng-click="infoBox.width = '300px'">small</button>
  <button ng-click="infoBox.width = '800px'">large</button>
</div>

在处理 ng-list 时,您甚至可能不需要对象相等性,即 $scope.$watch('scores', recalculateInfoBox); 应该也可以工作。

【讨论】:

    猜你喜欢
    • 2013-03-29
    • 2013-05-19
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    相关资源
    最近更新 更多