AngularJS: detecta automáticamente cambios en el modelo

103

Supongamos que quisiera hacer algo como ejecutar automáticamente algún código (como guardar datos en un servidor) cada vez que cambian los valores de un modelo. ¿Es la única forma de hacer esto estableciendo algo como ng-changeen cada control que posiblemente podría alterar el modelo?

Es decir, con las vistas, las cosas cambian correctamente a medida que se cambia el modelo sin tener que conectar nada explícitamente. ¿Existe una analogía con la posibilidad de ejecutar código que se guarda en un servidor? Algo como

myModel.on('change', function() {
  $.post("/my-url", ...);
});

como puede ver con algo como la columna vertebral.

Alec
fuente

Respuestas:

151

En las vistas con {{}}y / o ng-model, Angular está configurando $watch()es para usted detrás de escena.

Por defecto $watchcompara por referencia. Si se establece el tercer parámetro a $watchque true, en su lugar angular "superficial" ver el objeto de cambios. Para las matrices, esto significa comparar los elementos de la matriz; para los mapas de objetos, esto significa observar las propiedades. Entonces esto debería hacer lo que quieres:

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

Actualización : Angular v1.2 agregó un nuevo método para esto, `$ watchCollection () :

$scope.$watchCollection('myModel', function() { ... });

Tenga en cuenta que la palabra "superficial" se usa para describir la comparación en lugar de "profunda" porque las referencias no se siguen; por ejemplo, si el objeto observado contiene un valor de propiedad que es una referencia a otro objeto, esa referencia no se sigue para comparar el otro objeto.

Mark Rajcok
fuente
1
¡Ah, genial! ¿Hay alguna razón por la que esto no parece estar tan documentado (es decir, no creo que ninguno de los tutoriales en el sitio angular mencione la configuración de $ watches directamente)? ¿Hay algo malo en esto que haría que configurar (potencialmente múltiples) ng-changeganchos en los controles de entrada sea una mejor idea?
Alec
12
Sí, sería bueno si el tutorial principal mencionara $ watch en alguna parte. Lo "malo" de este enfoque es que puede llevar mucho tiempo si su modelo es grande (cada ciclo de resumen, cada pulsación de tecla en un campo de entrada, hará que este modelo se revise profundamente, posiblemente varias veces) . En ese caso, serían mejores $ watch () es selectivos o select ng-change.
Mark Rajcok
8

Y si necesita diseñar los elementos de su formulario de acuerdo con su estado (modificado / no modificado) dinámicamente o para probar si algunos valores realmente han cambiado, puede usar el siguiente módulo, desarrollado por mí mismo: https://github.com/betsol / entrada-angular-modificada

Agrega propiedades y métodos adicionales al formulario y sus elementos secundarios. Con él, puede probar si algún elemento contiene nuevos datos o incluso probar si todo el formulario tiene nuevos datos no guardados.

Puede configurar el siguiente reloj: $scope.$watch('myForm.modified', handler)y se llamará a su controlador si algunos elementos del formulario realmente contienen nuevos datos o si se invirtió al estado inicial.

Además, puede usar la modifiedpropiedad de elementos de formulario individuales para reducir realmente la cantidad de datos enviados a un servidor a través de una llamada AJAX. No es necesario enviar datos sin cambios.

Como beneficio adicional, puede revertir su formulario al estado inicial mediante una llamada al reset()método del formulario .

Puede encontrar la demostración del módulo aquí: http://plnkr.co/edit/g2MDXv81OOBuGo6ORvdt?p=preview

¡Salud!

Slava Fomin II
fuente
¿Hay alguna forma de verificar esto en el controlador? por ejemplo, si hago clic en el botón x, ¿puedo hacer como un if (myform.modified) mostrar una ventana emergente de confirmación?
Flash
Por supuesto, simplemente pase FormController a la función de su controlador: <form name="myForm">, <button ng-click="vm.doSomething(myForm)">.
Slava Fomin II
gracias, esto hará algo solo si el formulario fue modificado, ¿verdad?
Flash
Esto pasará FormControllera la doSomething()función de su controlador. Puede hacer lo que quiera con él dentro de esa función, por ejemplo, comprobar si el formulario está realmente modificado comprobando la FormController.modifiedpropiedad booleana.
Slava Fomin II
¡Gracias! Buena característica
Flash