【问题标题】:How to $watch changes on models created by ng-repeat?如何 $watch 由 ng-repeat 创建的模型的变化?
【发布时间】:2013-11-30 05:00:03
【问题描述】:

this Plnkr 为例。我不知道会预先创建多少fooCollection 的成员。所以我不知道会有多少bar 模型存在。

但我知道它们将是角度模型,并且我知道它们将在哪里。

我如何在这些上设置$watch

我需要这样做,因为我需要在 bar 模型更改时触发行为。只看 fooCollection 本身是不够的,$watch 监听器不会在 bar 更改时触发。

相关html:

<body ng-controller="testCtrl">
  <div ng-repeat="(fooKey, foo) in fooCollection">
    Tell me your name: <input ng-model="foo.bar">
    <br />
    Hello, my name is {{ foo.bar }}
  </div>
  <button ng-click="fooCollection.push([])">Add a Namer</button>
</body>

相关JS:

angular
.module('testApp', [])
.controller('testCtrl', function ($scope) {
  $scope.fooCollection = [];

  $scope.$watch('fooCollection', function (oldValue, newValue) {
    if (newValue != oldValue)
      console.log(oldValue, newValue);
  });
});

【问题讨论】:

    标签: angularjs angularjs-scope angularjs-ng-repeat


    【解决方案1】:

    尝试这样做

     <div ng-repeat="foo in fooCollection" ng-click="select(foo)">Tell me your ame:
            <input ng-model="foo.bar" ng-change="fooChanged(foo)">
            <br />Hello, my name is {{foo.bar}}</div>
            <button ng-click="fooCollection.push({})">Add a Namer</button>
     </div>
    

    Directive/Controller中有代码

     $scope.selectedfoo = {};
     $scope.select = (foo) => {
        $scope.selectedfoo = foo;
     }
    
     $scope.$watch('selectedfoo ', (newVal, oldVal) => {
      if (newVal) {
    
      }
     },true)
    

    【讨论】:

      【解决方案2】:

      创建单独的列表项控制器:demo on Plnkr

      js

      angular
        .module('testApp', [])
        .controller('testCtrl', function ($scope) {
          $scope.fooCollection = [];
        })
        .controller('fooCtrl', function ($scope) {
          $scope.$watch('foo.bar', function (newValue, oldValue) {
            console.log('watch fired, new value: ' + newValue);
          });
        });
      

      HTML

      <html ng-app="testApp">
        <body ng-controller="testCtrl">
          <div ng-repeat="(fooKey, foo) in fooCollection" ng-controller="fooCtrl">
            Tell me your name: <input ng-model="foo.bar" ng-change="doSomething()">
            <br />
            Hello, my name is {{ foo.bar }}
          </div>
          <button ng-click="fooCollection.push([])">Add a Namer</button>
        </body>
      </html>
      

      【讨论】:

      • 哇。我需要更多地考虑控制器是 Angular 的一等公民,以便将行为附加到 any 范围。
      • 只是一条评论,提醒用户切勿将链接到外部网站。您必须在答案正文中提供代码。我和OP有同样的问题,一个plnkr链接断开了,所以这个答案没用:(
      • 这没有回答最初的问题:如何监视 ng-repeat 集合中的项目。这个嵌套控制器中的 $watch 代码是什么?
      • 从 plunkr 复制了相关代码,因此答案再次变得有用 ;-)。
      • 有人能解释一下为什么需要两个控制器吗?
      【解决方案3】:

      如果您的收藏已填充,您可以在 ng-repeat 的每个项目上放置一个手表:

      html

      <div ng-repeat="item in items">
         {{ item.itemField }}
      </div>
      

      js

      for (var i = 0; i < $scope.items.length; i++) {
         $scope.$watch('items[' + i + ']', function (newValue, oldValue) {
            console.log(newValue.itemField + ":::" + oldValue.itemField);
         }, true);
      }
      

      【讨论】:

        【解决方案4】:

        由于我不想要另一个控制器,我最终改用 ng-change

        简单的jsFiddle:https://jsfiddle.net/maistho/z0xazw5n/

        相关 HTML:

        <body ng-app="testApp" ng-controller="testCtrl">
            <div ng-repeat="foo in fooCollection">Tell me your name:
                <input ng-model="foo.bar" ng-change="fooChanged(foo)">
                <br />Hello, my name is {{foo.bar}}</div>
            <button ng-click="fooCollection.push({})">Add a Namer</button>
        </body>
        

        相关JS:

        angular.module('testApp', [])
            .controller('testCtrl', function ($scope) {
            $scope.fooCollection = [];
        
            $scope.fooChanged = function (foo) {
                console.log('foo.bar changed, new value of foo.bar is: ', foo.bar);
            };
        });
        

        【讨论】:

        • 我认为 ng-change 比添加嵌套控制器更好。
        • ng-change 简洁、简洁、清晰。添加嵌套控制器很复杂,没有必要
        【解决方案5】:

        您还可以创建一个自定义指令,告诉您的主控制器进行更改

        YourModule.directive("batchWatch",[function(){
        return {
            scope:"=",
            replace:false,
            link:function($scope,$element,$attrs,Controller){
                $scope.$watch('h',function(newVal,oldVal){
                    if(newVal !== oldVal){
                      Controller.updateChange(newVal,oldVal,$scope.$parent.$index);
                    }
        
                },true);
        
            },
            controller:"yourController"
        };
        }]);
        

        假设你的标记是这样的

        <ul>
          <li ng-repeat="h in complicatedArrayOfObjects">
              <input type="text" ng-model="someModel" batch-watch="$index" />
          </li>
        </ul>
        

        这是你的控制器

        YourModule.controller("yourController",[$scope,function($scope){
            this.updateChange = function(newVal,oldVal,indexChanged){
              console.log("Details about the change");
            }
        }]);
        

        您还可以使用位于前 3 个参数、作用域、元素和属性的指令链接函数提供的值。

        【讨论】:

          【解决方案6】:

          您可以将 true 作为第三个参数传递给 $watch

          $scope.$watch('something', function() { doSomething(); }, true);
          

          https://docs.angularjs.org/api/ng/type/$rootScope.Scope

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-12-07
            • 2016-05-15
            • 1970-01-01
            • 2014-09-04
            • 2017-01-30
            相关资源
            最近更新 更多