Как отслеживать изменения в моделях, созданных ng-repeat?

StackOverflow https://stackoverflow.com//questions/20024156

Вопрос

Учитывать этот Планкр например.Я не знаю, сколько членов 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);
  });
});
Это было полезно?

Решение

Создайте отдельные контроллеры элементов списка: демо на 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>

Другие советы

Если ваша коллекция заполнена, вы можете наблюдать за каждым элементом 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);
}

Вы можете передать true в качестве третьего аргумента в $watch.

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

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

Вы также можете создать специальную директиву, которая будет сообщать вашему основному контроллеру об изменениях.

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");
    }
}]);

Вы также можете поиграть со значением, предоставленным функцией ссылки директивы, которая находится на первых трех аргументах: области действия, элементе и атрибуте.

Поскольку мне не нужен был другой контроллер, я в итоге использовал нг-изменение вместо.

Простой 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);
    };
});

Попробуй сделать это

 <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>

В Директиве/Контроллере есть код

 $scope.selectedfoo = {};
 $scope.select = (foo) => {
    $scope.selectedfoo = foo;
 }

 $scope.$watch('selectedfoo ', (newVal, oldVal) => {
  if (newVal) {

  }
 },true)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top