for angularjs watch

for - ¿Cómo mirar en profundidad una matriz en angularjs?



ng-repeat angularjs (10)

Hay una matriz de objetos en mi alcance, quiero ver todos los valores de cada objeto.

Este es mi código:

function TodoCtrl($scope) { $scope.columns = [ { field:''title'', displayName: ''TITLE''}, { field: ''content'', displayName: ''CONTENT'' } ]; $scope.$watch(''columns'', function(newVal) { alert(''columns changed''); }); }

Pero cuando TITLE2 los valores, por ejemplo, cambio TITLE a TITLE2 , la alert(''columns changed'') nunca apareció.

¿Cómo observar a fondo los objetos dentro de una matriz?

Hay una demostración en vivo: http://jsfiddle.net/SYx9b/


Aquí hay una comparación de las 3 formas en que puede ver una variable de alcance con ejemplos:

$ watch () es activado por:

$scope.myArray = []; $scope.myArray = null; $scope.myArray = someOtherArray;

$ watchCollection () es activado por todo lo que está arriba Y:

$scope.myArray.push({}); // add element $scope.myArray.splice(0, 1); // remove element $scope.myArray[0] = {}; // assign index to different value

$ watch (..., true) es activado por TODO lo de arriba Y:

$scope.myArray[0].someProperty = "someValue";

SOLO UNA COSA MÁS...

$ watch () es el único que se activa cuando una matriz se reemplaza por otra matriz, incluso si esa otra matriz tiene el mismo contenido exacto.

Por ejemplo, donde $watch() se $watchCollection() y $watchCollection() no:

$scope.myArray = ["Apples", "Bananas", "Orange" ]; var newArray = []; newArray.push("Apples"); newArray.push("Bananas"); newArray.push("Orange"); $scope.myArray = newArray;

A continuación se muestra un enlace a un ejemplo de JSFiddle que utiliza todas las diferentes combinaciones de relojes y envía mensajes de registro para indicar qué "relojes" fueron activados

http://jsfiddle.net/luisperezphd/2zj9k872/


Definir el parámetro objectEquality (tercer parámetro) de la función $watch es definitivamente la forma correcta de ver TODAS las propiedades de la matriz.

$scope.$watch(''columns'', function(newVal) { alert(''columns changed''); },true); // <- Right here

responde esto suficientemente bien y menciona $watchCollection también.

Mas detalle

La razón por la que a una pregunta ya contestada es porque quiero señalar que la respuesta de no es buena y no se debe usar.

El problema es que los compendios no suceden inmediatamente. Deben esperar hasta que el bloque de código actual se haya completado antes de ejecutarse. Por lo tanto, ver la length de una matriz puede pasar por alto algunos cambios importantes que $watchCollection detectará.

Asume esta configuración:

$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''); });

A primera vista, puede parecer que estos dispararían al mismo tiempo, como en este caso:

function pushToArray() { $scope.testArray.push({val:3}); } pushToArray(); // Console output // length changed: 2 -> 3 // testArray changed

Eso funciona bastante bien, pero considera esto:

function spliceArray() { // Starting at index 1, remove 1 item, then push {val: 3}. $testArray.splice(1, 1, {val: 3}); } spliceArray(); // Console output // testArray changed

Tenga en cuenta que la longitud resultante fue la misma, aunque la matriz tiene un elemento nuevo y perdió un elemento, por lo que, en lo que respecta al $watch , la length no ha cambiado. $watchCollection detectó.

function pushPopArray() { $testArray.push({val: 3}); $testArray.pop(); } pushPopArray(); // Console output // testArray change

El mismo resultado ocurre con un push y pop en el mismo bloque.

Conclusión

Para ver cada propiedad en la matriz, use $watch en la matriz con el tercer parámetro (objectEquality) incluido y establecido en verdadero. Sí, esto es caro pero a veces es necesario.

Para ver cuándo un objeto ingresa / sale de la matriz, use $watchCollection .

NO use un $watch en la propiedad length del array. Casi no hay una buena razón para pensar en hacerlo.


En mi caso, necesitaba ver un servicio, que contiene un objeto de dirección también observado por varios otros controladores. Me quedé atrapado en un bucle hasta que agregué el parámetro ''verdadero'', que parece ser la clave del éxito al observar objetos.

$scope.$watch(function() { return LocationService.getAddress(); }, function(address) { //handle address object }, true);


Esta solución funcionó muy bien para mí, lo hago en una directiva:

alcance. $ watch (attrs.testWatch, function () {.....}, true);

el verdadero funciona bastante bien y reacciona para todos los cambios (agregar, eliminar o modificar un campo).

Aquí hay un plunker de trabajo para jugar con él.

Profundamente viendo una matriz en AngularJS

Espero que esto te sea de utilidad. Si tiene alguna pregunta, no dude en preguntar, intentaré ayudar :)


Hay consecuencias en el rendimiento de sumergir un objeto en tu $ watch. A veces (por ejemplo, cuando los cambios solo son impulsos y saltos), es posible que desee ver un valor calculado fácilmente, como array.length.



Si vas a ver solo una matriz, simplemente puedes usar este bit de código:

$scope.$watch(''columns'', function() { // some value in the array has changed }, true); // watching properties

example

Pero esto no funcionará con múltiples arreglos:

$scope.$watch(''columns + ANOTHER_ARRAY'', function() { // will never be called when things change in columns or ANOTHER_ARRAY }, true);

example

Para manejar esta situación, normalmente convierto los múltiples arreglos que quiero ver en JSON:

$scope.$watch(function() { return angular.toJson([$scope.columns, $scope.ANOTHER_ARRAY, ... ]); }, function() { // some value in some array has changed }

example

Como @jssebastian señaló en los comentarios, JSON.stringify puede ser preferible a angular.toJson ya que puede manejar miembros que comienzan con ''$'' y también otros casos posibles.


Vale la pena señalar que en Angular 1.1.xy superior, ahora puede usar $watchCollection lugar de $ watch. Aunque el $ watchCollection parece crear relojes poco profundos, por lo que no funcionará con matrices de objetos como usted espera. Puede detectar adiciones y eliminaciones de la matriz, pero no las propiedades de los objetos dentro de las matrices.


$ watchCollection logra lo que quieres hacer. A continuación se muestra un ejemplo copiado del sitio web de angularjs http://docs.angularjs.org/api/ng/type/$rootScope.Scope Aunque es conveniente, el rendimiento debe tenerse en cuenta, especialmente cuando se ve una gran colección.

$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);


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