Как глубоко смотреть массив в angularjs?
в моей области есть массив объектов, я хочу посмотреть все значения каждого объекта.
Это мой код:
function TodoCtrl($scope) {
$scope.columns = [
{ field:'title', displayName: 'TITLE'},
{ field: 'content', displayName: 'CONTENT' }
];
$scope.$watch('columns', function(newVal) {
alert('columns changed');
});
}
но когда я изменяю значения, например, я изменяю TITLE
to TITLE2
на alert('columns changed')
никогда не совал.
как глубоко наблюдать объекты внутри массива?
есть демо-версия:http://jsfiddle.net/SYx9b/
10 ответов:
вы можете установить 3-й аргумент
$watch
доtrue
:$scope.$watch('data', function (newVal, oldVal) { /*...*/ }, true);
посмотреть https://docs.angularjs.org/api/ng/type/метрики.Объем#$смотреть
С Углового 1.1.x вы также можете использовать $watchCollection для просмотра мелких часов (только "первый уровень") коллекции.
$scope.$watchCollection('data', function (newVal, oldVal) { /*...*/ });
см.https://docs.angularjs.org/api/ng/type/$rootScope. Scope#$watchCollection
есть последствия производительности для глубокого погружения объекта в вашем $watch. Иногда (например, когда изменения только выталкиваются и всплывают), вы можете захотеть $watch легко вычисляемое значение, такое как array.длина.
если вы собираетесь посмотреть только один массив, вы можете просто использовать этот кусок кода:
$scope.$watch('columns', function() { // some value in the array has changed }, true); // watching properties
но это не будет работать с несколькими массивами:
$scope.$watch('columns + ANOTHER_ARRAY', function() { // will never be called when things change in columns or ANOTHER_ARRAY }, true);
чтобы справиться с этой ситуацией, я обычно преобразую несколько массивов, которые я хочу посмотреть в JSON:
$scope.$watch(function() { return angular.toJson([$scope.columns, $scope.ANOTHER_ARRAY, ... ]); }, function() { // some value in some array has changed }
как @jssebastian указал в комментариях,
JSON.stringify
может быть предпочтительнееangular.toJson
поскольку он может обрабатывать элементы, которые начинаются с " $ " и возможных других случаев.
стоит отметить, что в угловых 1.1.X и выше, теперь вы можете использовать $watchCollection а не $ watch. Хотя $watchCollection, похоже, создает мелкие часы, поэтому он не будет работать с массивами объектов, как вы ожидаете. Он может обнаруживать добавления и удаления в массив, но не свойства объектов внутри массивов.
$watchCollection свершать то, что вы хотите сделать. Ниже приведен пример скопирован с сайта в AngularJS http://docs.angularjs.org/api/ng/type/метрики.Область Хотя это удобно, производительность должна быть принята во внимание, особенно когда вы смотрите большую коллекцию.
$scope.names = ['igor', 'matias', 'misko', 'james']; $scope.dataCount = 4; $scope.$watchCollection('names', function(newNames, oldNames) { $scope.dataCount = newNames.length; }); expect($scope.dataCount).toEqual(4); $scope.$digest(); //still at 4 ... no changes expect($scope.dataCount).toEqual(4); $scope.names.pop(); $scope.$digest(); //now there's been a change expect($scope.dataCount).toEqual(3);
вот сравнение 3 способов, которыми вы можете смотреть переменную scope с примерами:
$watch () запускается:
$scope.myArray = []; $scope.myArray = null; $scope.myArray = someOtherArray;
$watchCollection() запускается все выше и:
$scope.myArray.push({}); // add element $scope.myArray.splice(0, 1); // remove element $scope.myArray[0] = {}; // assign index to different value
$ watch(..., правда) запускается все выше и:
$scope.myArray[0].someProperty = "someValue";
ЕЩЕ ОДНА ВЕЩЬ...
$watch () это единственный, который срабатывает, когда массив заменяется другим массивом, даже если этот другой массив имеет то же самое точное содержимое.
здесь$watch()
будут стрелять и$watchCollection()
не будет:$scope.myArray = ["Apples", "Bananas", "Orange" ]; var newArray = []; newArray.push("Apples"); newArray.push("Bananas"); newArray.push("Orange"); $scope.myArray = newArray;
Ниже приведена ссылка на пример JSFiddle, который использует все различные комбинации часов и выводит сообщения журнала, чтобы указать, какие "часы" были вызваны:
Это решение работает очень хорошо для меня, я делаю это в директиву:
объем.$watch(attrs.testWatch, function () {.....}, true);
true работает довольно хорошо и реагирует на все chnages (добавление, удаление или изменение поля).
вот рабочий плунжер для игры с ним.
глубоко наблюдая за массивом в AngularJS
Я надеюсь, что это может быть полезным для вас. Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать, я буду попробую помочь :)
в моем случае мне нужно было наблюдать за сервисом, который содержит объект адреса, также наблюдаемый несколькими другими контроллерами. Я застрял в цикле, пока не добавил параметр "true", который, похоже, является ключом к успеху при просмотре объектов.
$scope.$watch(function() { return LocationService.getAddress(); }, function(address) { //handle address object }, true);
задание
objectEquality
параметр (третий параметр)$watch
функция, безусловно, правильный способ смотреть все свойства массива.$scope.$watch('columns', function(newVal) { alert('columns changed'); },true); // <- Right here
Пиран отвечает на это достаточно хорошо и упоминает
$watchCollection
как хорошо.Более Подробно
причина, по которой я отвечаю на уже ответленный вопрос, заключается в том, что я хочу указать, что wizardwerdnaответ не является хорошим и не должен быть используемый.
проблема в том, что переваривание происходит не сразу. Они должны дождаться завершения текущего блока кода перед выполнением. Таким образом, смотрите
length
массива может на самом деле пропустить некоторые важные изменения, которые$watchCollection
будет ловить.предположим, что эта конфигурация:
$scope.testArray = [ {val:1}, {val:2} ]; $scope.$watch('testArray.length', function(newLength, oldLength) { console.log('length changed: ', oldLength, ' -> ', newLength); }); $scope.$watchCollection('testArray', function(newArray) { console.log('testArray changed'); });
на первый взгляд может показаться, что они будут стрелять одновременно, например, в этом случае:
function pushToArray() { $scope.testArray.push({val:3}); } pushToArray(); // Console output // length changed: 2 -> 3 // testArray changed
это работает достаточно хорошо, но рассмотрим это:
function spliceArray() { // Starting at index 1, remove 1 item, then push {val: 3}. $testArray.splice(1, 1, {val: 3}); } spliceArray(); // Console output // testArray changed
обратите внимание, что результирующая длина была такой же, даже если массив имеет новый элемент и потерял элемент, так как часы, как
$watch
обеспокоен,length
ничего не изменилось.$watchCollection
взял на него, хотя.function pushPopArray() { $testArray.push({val: 3}); $testArray.pop(); } pushPopArray(); // Console output // testArray change
тот же результат происходит с толчком и поп в том же блоке.
вывод
чтобы просмотреть каждое свойство в массиве, используйте
$watch
на массиве iteself с помощью третий параметр (objectEquality) включен и установлен в true. Да, это дорого, но иногда надо.чтобы наблюдать, когда объект входит / выходит из массива, используйте
$watchCollection
.не используйте
$watch
наlength
свойства массива. У меня почти нет веской причины так поступать.
$scope.changePass = function(data){ if(data.txtNewConfirmPassword !== data.txtNewPassword){ $scope.confirmStatus = true; }else{ $scope.confirmStatus = false; } };
<form class="list" name="myForm"> <label class="item item-input"> <input type="password" placeholder="ใส่รหัสผ่านปัจจุบัน" ng-model="data.txtCurrentPassword" maxlength="5" required> </label> <label class="item item-input"> <input type="password" placeholder="ใส่รหัสผ่านใหม่" ng-model="data.txtNewPassword" maxlength="5" ng-minlength="5" name="checknawPassword" ng-change="changePass(data)" required> </label> <label class="item item-input"> <input type="password" placeholder="ใส่รหัสผ่านใหม่ให้ตรงกัน" ng-model="data.txtNewConfirmPassword" maxlength="5" ng-minlength="5" name="checkConfirmPassword" ng-change="changePass(data)" required> </label> <div class="spacer" style="width: 300px; height: 5px;"></div> <span style="color:red" ng-show="myForm.checknawPassword.$error.minlength || myForm.checkConfirmPassword.$error.minlength">รหัสผ่านต้องมีจำนวน 5 หลัก</span><br> <span ng-show="confirmStatus" style="color:red">รหัสผ่านใหม่ไม่ตรงกัน</span> <br> <button class="button button-positive button-block" ng-click="saveChangePass(data)" ng-disabled="myForm.$invalid || confirmStatus">เปลี่ยน</button> </form>