Как глубоко смотреть массив в 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
to 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 рутскоп.Область#$watchCollection
есть последствия производительности для глубокого погружения объекта в ваших часах$. Иногда (например, когда изменения только толкают и всплывают), вы можете захотеть $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
как он может обрабатывать члены, которые начинаются с " $ " и возможных других случаев.
стоит отметить, что в Angular 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 способов просмотра переменной области с примерами:
$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>