Comment $watch les changements sur les modèles créés par ng-repeat ?
-
21-12-2019 - |
Question
Considérer ce Plnkr Par exemple.Je ne sais pas combien de membres fooCollection
sera créé au préalable.Donc je ne sais pas combien bar
des modèles vont exister.
Mais je sais que ce seront des modèles angulaires, et je sais où ils seront.
Comment puis-je faire un $watch
sur ceux-ci ?
Je dois le faire parce que je dois déclencher un comportement lorsqu'un bar
le modèle est modifié.Regarder fooCollection lui-même ne suffit pas, le $watch
l'écouteur ne se déclenche pas lorsqu'un bar
est changé.
HTML pertinent :
<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 pertinent :
angular
.module('testApp', [])
.controller('testCtrl', function ($scope) {
$scope.fooCollection = [];
$scope.$watch('fooCollection', function (oldValue, newValue) {
if (newValue != oldValue)
console.log(oldValue, newValue);
});
});
La solution
Créez des contrôleurs d'éléments de liste individuels : démo sur 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>
Autres conseils
Si votre collection est remplie, vous pouvez placer une surveillance sur chaque élément du 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);
}
Vous pouvez passer true comme troisième argument dans $watch
$scope.$watch('something', function() { doSomething(); }, true);
Vous pouvez également créer une directive personnalisée qui indiquera à votre contrôleur principal les modifications
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"
};
}]);
supposez que votre balisage est comme ça
<ul>
<li ng-repeat="h in complicatedArrayOfObjects">
<input type="text" ng-model="someModel" batch-watch="$index" />
</li>
</ul>
et voici votre contrôleur
YourModule.controller("yourController",[$scope,function($scope){
this.updateChange = function(newVal,oldVal,indexChanged){
console.log("Details about the change");
}
}]);
Vous pouvez également jouer avec la valeur fournie par la fonction de lien de directive qui repose sur les 3 premiers arguments, scope, element et attr.
Comme je ne voulais pas d'autre contrôleur, j'ai fini par utiliser ng-changement plutôt.
JsFiddle simple : https://jsfiddle.net/maistho/z0xazw5n/
HTML pertinent :
<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 pertinent :
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);
};
});
Essayez de faire ça
<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>
Il y a le code dans Directive/Contrôleur
$scope.selectedfoo = {};
$scope.select = (foo) => {
$scope.selectedfoo = foo;
}
$scope.$watch('selectedfoo ', (newVal, oldVal) => {
if (newVal) {
}
},true)