¿Cómo uso $scope.$watch y $scope.$apply en AngularJS?
Frecuentes
Visto 996,942 veces
1121
No entiendo como usar $scope.$watch
y $scope.$apply
. La documentación oficial no es útil.
Lo que no entiendo específicamente:
- ¿Están conectados al DOM?
- ¿Cómo puedo actualizar los cambios de DOM en el modelo?
- ¿Cuál es el punto de conexión entre ellos?
Lo intenté este tutorial, pero se necesita la comprensión de $watch
y $apply
por sentado
Qué hacer $apply
y $watch
hacer, y cómo los uso apropiadamente?
6 Respuestas
1783
Debe conocer cómo funciona AngularJS para comprenderlo.
Ciclo de resumen y $scope
En primer lugar, AngularJS define un concepto de lo que se denomina ciclo de digestión. Este ciclo se puede considerar como un bucle, durante el cual AngularJS comprueba si hay cambios en todas las variables. mirado por todos los $scope
s. entonces si tienes $scope.myVar
definido en su controlador y esta variable fue marcado para ser observado, entonces le está diciendo implícitamente a AngularJS que controle los cambios en myVar
en cada iteración del bucle.
Una pregunta de seguimiento natural sería: ¿Está todo unido a $scope
¿Siendo vigilado? Afortunadamente, no. Si observara los cambios en cada objeto de su $scope
, luego, rápidamente, un ciclo de resumen tardaría años en evaluarse y rápidamente se encontraría con problemas de rendimiento. Es por eso que el equipo de AngularJS nos dio dos formas de declarar algunos $scope
variable como siendo observado (leer más abajo).
$watch ayuda a escuchar los cambios de $scope
Hay dos formas de declarar un $scope
variable como siendo observado.
- Al usarlo en su plantilla a través de la expresión
<span>{{myVar}}</span>
- Agregándolo manualmente a través del
$watch
excepcional
Anuncio 1) Este es el escenario más común y estoy seguro de que lo has visto antes, pero no sabías que esto ha creado un reloj en segundo plano. ¡Sí, lo tenía! Usando directivas AngularJS (como ng-repeat
) también puede crear relojes implícitos.
Anuncio 2) Así es como creas el tuyo relojes. $watch
El servicio lo ayuda a ejecutar algún código cuando se adjunta algún valor al $scope
ha cambiado. Rara vez se usa, pero a veces es útil. Por ejemplo, si desea ejecutar algún código cada vez que cambia 'myVar', puede hacer lo siguiente:
function MyController($scope) {
$scope.myVar = 1;
$scope.$watch('myVar', function() {
alert('hey, myVar has changed!');
});
$scope.buttonClicked = function() {
$scope.myVar = 2; // This will trigger $watch expression to kick in
};
}
$apply permite integrar cambios con el ciclo de resumen
Puedes pensar en el $apply
funcionan como un mecanismo de integración. Verás, cada vez que cambias algo variable observada adjunta a la $scope
object directamente, AngularJS sabrá que el cambio ha ocurrido. Esto se debe a que AngularJS ya sabía monitorear esos cambios. Entonces, si sucede en el código administrado por el marco, el ciclo de resumen continuará.
Sin embargo, a veces quieres cambiar algún valor fuera del mundo AngularJS y ver los cambios propagarse normalmente. Considere esto: usted tiene un $scope.myVar
valor que se modificará dentro de un jQuery $.ajax()
manipulador. Esto sucederá en algún momento en el futuro. AngularJS no puede esperar a que esto suceda, ya que no se le ha indicado que espere en jQuery.
Para abordar esto, $apply
ha sido introducido. Le permite iniciar el ciclo de digestión de forma explícita. Sin embargo, solo debe usar esto para migrar algunos datos a AngularJS (integración con otros marcos), pero nunca use este método combinado con el código AngularJS normal, ya que AngularJS arrojará un error en ese momento.
¿Cómo se relaciona todo esto con el DOM?
Bueno, realmente deberías seguir el tutorial nuevamente, ahora que sabes todo esto. El ciclo de resumen se asegurará de que la interfaz de usuario y el código JavaScript permanezcan sincronizados, al evaluar cada observador adjunto a todos $scope
s siempre y cuando nada cambie. Si no se producen más cambios en el bucle de resumen, se considera que ha finalizado.
Puede adjuntar objetos a la $scope
objeto ya sea explícitamente en el Controlador, o declarándolos en {{expression}}
formulario directamente en la vista.
Lecturas adicionales:
Respondido 31 ago 21, 06:08
163
En AngularJS, actualizamos nuestros modelos y nuestras vistas/plantillas actualizan el DOM "automáticamente" (a través de directivas integradas o personalizadas).
$apply y $watch, ambos métodos de Scope, no están relacionados con el DOM.
EL Conceptos La página (sección "Tiempo de ejecución") tiene una explicación bastante buena del bucle $digest, $apply, la cola $evalAsync y la lista $watch. Esta es la imagen que acompaña al texto:
Cualquier código que tenga acceso a un alcance, normalmente controladores y directivas (sus funciones de enlace y/o sus controladores), puede configurar un "verExpresión" que AngularJS evaluará contra ese alcance. Esta evaluación ocurre cada vez que AngularJS ingresa a su bucle $digest (en particular, el bucle "$watch list"). Puede ver propiedades de alcance individuales, puede definir una función para ver dos propiedades juntas, puede ver la longitud de una matriz, etc.
Cuando las cosas suceden "dentro de AngularJS", por ejemplo, escribe en un cuadro de texto que tiene habilitado el enlace de datos bidireccional de AngularJS (es decir, usa el modelo ng), se dispara una devolución de llamada $http, etc. - Ya se ha llamado a $apply, por lo que Estás dentro del rectángulo "AngularJS" en la figura de arriba. Se evaluarán todas las watchExpressions (posiblemente más de una vez, hasta que no se detecten más cambios).
Cuando las cosas suceden "fuera de AngularJS", por ejemplo, usó bind() en una directiva y luego se activa ese evento, lo que da como resultado que se llame a su devolución de llamada, o que se activen algunas devoluciones de llamada registradas con jQuery, todavía estamos en el rectángulo "Nativo". Si el código de devolución de llamada modifica cualquier cosa que cualquier $watch esté viendo, llame a $apply para ingresar al rectángulo de AngularJS, lo que hace que se ejecute el bucle $digest y, por lo tanto, AngularJS notará el cambio y hará su magia.
Respondido 02 Feb 16, 08:02
Entiendo la idea, lo que no entiendo es cómo se transfieren realmente los datos. Tengo un modelo que es un objeto con muchos datos, uso algunos para manipular el DOM. entonces algo de eso se cambia. ¿Cómo coloco los datos modificados en el lugar correcto en el modelo? En el ejemplo que usé, él hace la manipulación y al final simplemente usa scope.$apply(scope.model)
, no entiendo qué datos se transfieren y cómo se transfieren al lugar correcto en el modelo. - Ilio
No se está produciendo ninguna transferencia mágica de datos. Normalmente, con las aplicaciones de Angular, debe cambiar los modelos de Angular, que luego impulsan las actualizaciones de vista/DOM. Si actualiza el DOM fuera de Angular, deberá actualizar manualmente los modelos. scope.$apply(scope.model)
simplemente evaluará scope.model
como una expresión angular, y luego ingrese un ciclo $digest. En el artículo al que hace referencia, probablemente scope.$apply()
sería suficiente, ya que el modelo ya se está viendo. La función stop() está actualizando el modelo (creo que toUpdate es una referencia a scope.model), y luego se llama a $apply. - Marcos Rajcok
Parece que los documentos de AngularJS se han desplazado debajo de esta respuesta (el primer enlace no tiene "tiempo de ejecución" o $watch
en la página, y el segundo enlace está roto -- a partir de ahora, de todos modos). Penosamente, las versiones de archivo no almacenó en caché el proceso asincrónico que creó el contenido. - ruffin
55
AngularJS extiende esto bucle de eventos, creando algo llamado AngularJS context
.
$ reloj ()
Cada vez que vincula algo en la interfaz de usuario, inserta un $watch
en un parche de $watch
--.
User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
Aquí tenemos $scope.user
, que está vinculado a la primera entrada, y tenemos $scope.pass
, que está ligado al segundo. Haciendo esto sumamos dos $watch
es a la $watch
--.
Cuando nuestro plantilla está cargado, también conocido como en la fase de vinculación, el compilador buscará todas las directivas y creará todas las $watch
es que se necesitan.
AngularJS proporciona $watch
, $watchcollection
y $watch(true)
. A continuación se muestra un diagrama ordenado que explica los tres tomados de observadores en profundidad.
angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
$scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];
$scope.$watch("users", function() {
console.log("**** reference checkers $watch ****")
});
$scope.$watchCollection("users", function() {
console.log("**** Collection checkers $watchCollection ****")
});
$scope.$watch("users", function() {
console.log("**** equality checkers with $watch(true) ****")
}, true);
$timeout(function(){
console.log("Triggers All ")
$scope.users = [];
$scope.$digest();
console.log("Triggers $watchCollection and $watch(true)")
$scope.users.push({ name: 'Thalaivar'});
$scope.$digest();
console.log("Triggers $watch(true)")
$scope.users[0].name = 'Superstar';
$scope.$digest();
});
}
$digest
loops
Cuando el navegador recibe un evento que puede ser administrado por el contexto AngularJS, el $digest
se activará el bucle. Este lazo está hecho de dos lazos más pequeños. Uno procesa el $evalAsync
cola, y el otro procesa el $watch list
. $digest
recorrerá la lista de $watch
eso tenemos
app.controller('MainCtrl', function() {
$scope.name = "vinoth";
$scope.changeFoo = function() {
$scope.name = "Thalaivar";
}
});
{{ name }}
<button ng-click="changeFoo()">Change the name</button>
Aquí solo tenemos uno $watch
porque ng-click no crea ningún reloj.
Presionamos el botón.
- El navegador recibe un evento que ingresará al contexto AngularJS
- EL
$digest
loop se ejecutará y le preguntará a cada $watch por cambios. - Puesto que el
$watch
que estaba buscando cambios en $scope.name informa un cambio, forzará otro$digest
lazo. - El nuevo bucle no informa nada.
- El navegador recupera el control y actualizará el DOM reflejando el nuevo valor de $scope.name
- Lo importante aquí es que CADA evento que ingrese al contexto de AngularJS ejecutará un
$digest
círculo. Eso significa que cada vez que escribimos una letra en una entrada, el bucle se ejecutará comprobando cada$watch
en esta pagina
$ aplicar ()
Si llamas $apply
cuando se activa un evento, pasará por el contexto angular, pero si no lo llama, se ejecutará fuera de él. Es tan fácil como eso. $apply
llamará al $digest()
loop internamente e iterará sobre todos los relojes para garantizar que el DOM se actualice con el valor recién actualizado.
EL $apply()
El método activará a los observadores en todo el $scope
cadena mientras que el $digest()
El método solo activará los observadores en el actual $scope
y su children
. Cuando ninguno de los de arriba $scope
los objetos necesitan saber acerca de los cambios locales, puede usar $digest()
.
Respondido el 20 de junio de 20 a las 10:06
18
Encontré videos muy detallados que cubren $watch
, $apply
, $digest
y digerir ciclos en:
AngularJS: comprensión de Watcher, $watch, $watchGroup, $watchCollection, ng-change
Tutorial de AngularJS: comprensión de $apply y $digest (en profundidad)
A continuación hay un par de diapositivas utilizadas en esos videos para explicar los conceptos (por si acaso, si los enlaces anteriores se eliminan o no funcionan).
En la imagen de arriba, "$scope.c" no se ve porque no se usa en ninguno de los enlaces de datos (en el marcado). Los otros dos ($scope.a
y $scope.b
) será vigilado.
De la imagen de arriba: según el evento del navegador respectivo, AngularJS captura el evento, realiza un ciclo de resumen (recorre todos los relojes en busca de cambios), ejecuta funciones de reloj y actualiza el DOM. Si no son eventos del navegador, el ciclo de resumen se puede activar manualmente usando $apply
or $digest
.
Más información sobre $apply
y $digest
:
Respondido el 07 de enero de 17 a las 15:01
17
Existen $watchGroup
y $watchCollection
también. Específicamente, $watchGroup
es realmente útil si desea llamar a una función para actualizar un objeto que tiene múltiples propiedades en una vista que no es un objeto dom, por ejemplo, otra vista en el lienzo, WebGL o solicitud del servidor.
Aquí, la documentación aquí.
Respondido 19 Abr '20, 12:04
habría comentado sobre el $watchCollection
pero veo que ya lo hiciste. Aquí está la documentación al respecto desde el sitio AngularJS. Proporcionan una imagen muy agradable de la $watch
profundidad. Tenga en cuenta que la información está cerca de la parte inferior de la página. - JabberwockyDescompilador
15
Acabo de terminar de leer TODO lo anterior, aburrido y soñoliento (perdón pero es verdad). Muy técnico, profundo, detallado y seco. ¿Por qué estoy escribiendo? Debido a que AngularJS es masivo, muchos conceptos interconectados pueden volver loco a cualquiera. A menudo me preguntaba, ¿no soy lo suficientemente inteligente como para entenderlos? ¡No! Es porque muy pocos pueden explicar la tecnología en un lenguaje para tontos ¡sin todas las terminologías! Bien, déjame probar:
1) Todas son cosas impulsadas por eventos. (Oigo la risa, pero sigue leyendo)
Si no sabe qué es la función basada en eventos, entonces piense que coloca un botón en la página, conéctelo con una función usando "al hacer clic", esperando que los usuarios hagan clic en él para activar las acciones que plante dentro de la página. función. O piense en el "disparador" de SQL Server/Oracle.
2) $ reloj es "al hacer clic".
Lo que tiene de especial es que toma 2 funciones como parámetros, la primera da el valor del evento, la segunda toma el valor en consideración...
3) $digest es el jefe que revisa incansablemente, bla-bla-bla pero un buen jefe.
4) $apply te da el camino cuando quieres hacerlo manualmente, como una prueba de fallas (en caso de que el clic no se active, lo obliga a ejecutarse).
Ahora, hagámoslo visual. Imagínese esto para que sea aún más fácil captar la idea:
En un restaurante,
- MESERO
se supone que toman pedidos de los clientes, esto es
$watch(
function(){return orders;},
function(){Kitchen make it;}
);
- GERENTE corriendo para asegurarse de que todos los meseros estén despiertos, respondiendo a cualquier señal de cambio de los clientes. Esto es $digest()
- DUEÑO tiene el máximo poder para conducir a todos a pedido, esto es $apply()
Respondido el 20 de junio de 20 a las 10:06
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas angularjs angularjs-scope or haz tu propia pregunta.
¿Qué hay de usar esto? (método "Controlar como") - Leandro Bardelli
El uso de "Controlar como" no debería afectar a la información anterior. El uso de this.myVar pone myVar en el alcance. - Marcus Radell
@ŁukaszBachman - "entonces le está diciendo explícitamente a Angular que controle los cambios". Creo que es 'implícitamente' no 'explícitamente' - desaparecido en combate