new - scope broadcast angularjs
¿Cómo uso $ scope. $ Watch y $ scope. $ Apply en AngularJS? (7)
AngularJS extiende este bucle de eventos , creando algo llamado AngularJS context
.
$ reloj ()
Cada vez que vincula algo en la interfaz de usuario inserta un $watch
en una lista 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á vinculado a la segunda entrada. Haciendo esto agregamos dos $watch
es a la lista de $watch
.
Cuando se carga nuestra plantilla , también conocido como AKA en la fase de vinculación, el compilador buscará todas las directivas y creará todos los $watch
que se necesitan.
AngularJS proporciona $watch
, $watchcollection
y $watch(true)
. A continuación se muestra un diagrama ordenado que explica en profundidad los tres tomados de los observadores .
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
bucle de $digest
Cuando el navegador recibe un evento que puede ser administrado por el contexto de AngularJS, se activará el bucle $digest
. Este bucle está hecho de dos bucles más pequeños. Uno procesa la cola $evalAsync
, y el otro procesa la $watch list
. El $digest
recorrerá la lista de $watch
que 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 un $watch
porque ng-click no crea ningún reloj.
Pulsamos el botón.
- El navegador recibe un evento que entrará en el contexto de AngularJS.
- El bucle
$digest
se ejecutará y pedirá a cada $ watch los cambios. - Dado que el
$watch
que estaba observando los cambios en $ scope.name informa un cambio, forzará otro bucle$digest
. - 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 ingresa al contexto de AngularJS ejecutará un bucle
$digest
. Eso significa que cada vez que escribimos una letra en una entrada, el bucle se ejecutará revisando cada$watch
en esta página.
$ aplicar ()
Si llama a $apply
cuando se dispara 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 bucle $digest()
internamente e iterará sobre todos los relojes para garantizar que el DOM se actualice con el valor recién actualizado.
El método $apply()
activará a los observadores en toda la cadena $scope
, mientras que el método $digest()
solo activará a los observadores en el $scope
actual $scope
y sus children
. Cuando ninguno de los objetos de $scope
necesita conocer los cambios locales, puede usar $digest()
.
No entiendo cómo 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 al modelo?
- ¿Cuál es el punto de conexión entre ellos?
Intenté este tutorial , pero se toma en cuenta la comprensión de $watch
y $apply
.
¿Qué hacen $apply
y $watch
, y cómo los uso apropiadamente?
Debe conocer cómo funciona AngularJS para entenderlo.
Ciclo de digestión y $ alcance
En primer lugar, AngularJS define un concepto del denominado ciclo de digestión . Este ciclo puede considerarse como un bucle, durante el cual AngularJS verifica si hay cambios en todas las variables observadas por todos los $scope
s. Entonces, si tiene $scope.myVar
definido en su controlador y esta variable fue marcada para ser observada , entonces le está diciendo a AngularJS que monitoree los cambios en myVar
en cada iteración del bucle.
Una pregunta de seguimiento natural sería: ¿Se está observando todo lo relacionado con $scope
? Afortunadamente, no. Si vigilara los cambios en cada objeto en su $scope
, entonces rápidamente se demoraría en evaluar un ciclo de resumen y rápidamente se encontraría con problemas de rendimiento. Es por eso que el equipo de AngularJS nos dio dos formas de declarar una variable $scope
como observada (lea a continuación).
$ watch ayuda a escuchar $ cambios en el alcance
Hay dos formas de declarar una variable $scope
como vigilada.
-
<span>{{myVar}}</span>
en su plantilla a través de la expresión<span>{{myVar}}</span>
- Añadiéndolo manualmente a través del servicio
$watch
.
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 el fondo. Sí, lo tenía! El uso de directivas AngularJS (como ng-repeat
) también puede crear relojes implícitos.
Anuncio 2) Así es como creas tus propios relojes . $watch
servicio $watch
ayuda a ejecutar algunos códigos cuando se modifica algún valor asociado a $scope
. Rara vez se utiliza, 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.
Puede pensar en la función $apply
como en un mecanismo de integración . Verá, cada vez que cambie una variable observada adjunta al objeto $scope
directamente, AngularJS sabrá que el cambio ha ocurrido. Esto se debe a que AngularJS ya sabía monitorear esos cambios. Por lo tanto, si ocurre en un código administrado por el marco, el ciclo de resumen continuará.
Sin embargo, a veces desea cambiar algún valor fuera del mundo AngularJS y ver que los cambios se propagan normalmente. Considera esto: tienes un valor de $scope.myVar
que se modificará dentro del controlador $.ajax()
jQuery. Esto sucederá en algún momento en el futuro. AngularJS no puede esperar a que esto suceda, ya que no se le ha pedido que espere en jQuery.
Para abordar esto, se ha introducido $apply
. Te permite iniciar el ciclo de digestión explícitamente. 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 regular de AngularJS, ya que AngularJS generará un error.
¿Cómo se relaciona todo esto con el DOM?
Bueno, realmente deberías seguir el tutorial de nuevo, ahora que sabes todo esto. El ciclo de resumen garantizará que la interfaz de usuario y el código de JavaScript permanezcan sincronizados, evaluando cada observador adjunto a todos los $scope
s siempre que nada cambie. Si no ocurren más cambios en el bucle de resumen, se considera que está terminado.
Puede adjuntar objetos al objeto $scope
forma explícita en el Controlador o declarándolos en la forma {{expression}}
directamente en la vista.
Espero que ayude a aclarar algunos conocimientos básicos sobre todo esto.
Lecturas adicionales:
En AngularJS, actualizamos nuestros modelos, y nuestras vistas / plantillas actualizan el DOM "automáticamente" (a través de directivas incorporadas o personalizadas).
$ apply y $ watch, ambos métodos de alcance, no están relacionados con el DOM.
La página de Concepts (sección "Tiempo de ejecución") tiene una explicación bastante buena del bucle $ digest, $ apply, la cola $ evalAsync y la lista de $ watch. Aquí está la imagen que acompaña al texto:
Cualquiera que sea el código que tenga acceso a un alcance, normalmente los controladores y las directivas (sus funciones de enlace y / o sus controladores), puede configurar una " watchExpression " que AngularJS evaluará en relación con ese alcance. Esta evaluación ocurre cada vez que AngularJS ingresa su $ bucle de digestión (en particular, el bucle "$ lista de observación"). 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 suceden cosas "dentro de AngularJS": p. Ej., Escribe en un cuadro de texto que tiene el enlace de datos bidireccional AngularJS habilitado (es decir, utiliza el modelo ng), se activa una devolución de llamada $ http, etc. 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 suceden cosas "fuera de AngularJS", por ejemplo, usó bind () en una directiva y luego ese evento se activa, lo que resulta en que se llame su devolución de llamada, o en algunos incendios de devolución de llamada registrados de jQuery - todavía estamos en el rectángulo "Nativo". Si el código de devolución de llamada modifica cualquier cosa que esté viendo cualquier $ watch, 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.
Encontré videos muy profundos que cubren $watch
, $apply
, $digest
y digerir ciclos en:
AngularJS - Comprensión del observador, $ watch, $ watchGroup, $ watchCollection, ng-change
AngularJS Tutorial - Comprensión de $ apply y $ digest (en profundidad)
A continuación hay un par de diapositivas usadas 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 está viendo ya que no se utiliza en ninguno de los enlaces de datos (en el marcado). Los otros dos ( $scope.a
y $scope.b
) serán vigilados.
De la imagen anterior: basado en el evento del navegador respectivo, AngularJS captura el evento, realiza un ciclo de resumen (pasa por todos los controles de los cambios), ejecuta las funciones de observación y actualiza el DOM. Si no son eventos del navegador, el ciclo de resumen se puede activar manualmente usando $apply
o $digest
.
Más sobre $apply
y $digest
:
Solo termina de leer TODO lo anterior, aburrido y somnoliento (lo siento pero es cierto). Muy técnico, en profundidad, detallado y seco. ¿Por qué estoy escribiendo? Debido a que AngularJS es masivo, muchos conceptos interconectados pueden volver loco a cualquiera que se esté volviendo loco. 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 dummie sin todas las terminologías! Está bien, déjame intentarlo:
1) Todas son cosas impulsadas por eventos. (Oigo la risa, pero sigue leyendo)
Si no sabe qué es lo que impulsa el evento. Luego, piense que coloca un botón en la página, conéctelo con una función usando "clic", esperando a que los usuarios hagan clic en él para activar las acciones que usted planta dentro del función. O piense en el "disparador" de SQL Server / Oracle.
2) $ watch es "on-click".
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 al hacer clic no se active, lo obligas a correr).
Ahora, hagámoslo visual. Imagina esto para que sea aún más fácil captar la idea:
En un restaurante,
- Se espera que los WAITERS tomen órdenes de los clientes, esto es
$watch(
function(){return orders;},
function(){Kitchen make it;}
);
- EL ADMINISTRADOR corre alrededor para asegurarse de que todos los camareros estén despiertos y respondan a cualquier señal de cambio de los clientes. Esto es $digest()
- El PROPIETARIO tiene el máximo poder para conducir a todos los que lo soliciten, esto es $apply()
También hay $watchGroup
y $watchCollection
. 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 lienzo, webGL o solicitud de servidor. Aquí, el link la documentación.
Este blog ha sido cubierto todo lo que crea ejemplos y explicaciones comprensibles.
Las funciones de $watch(), $digest()
AngularJS $scope
$watch(), $digest()
y $apply()
son algunas de las funciones centrales de AngularJS. Comprender $watch()
, $digest()
y $apply()
es esencial para entender AngularJS.
Cuando crea un enlace de datos desde algún lugar de su vista a una variable en el objeto $ scope, AngularJS crea un "reloj" internamente. Un reloj significa que AngularJS observa cambios en la variable en el $scope object
. El marco es "observar" la variable. Los relojes se crean utilizando la función $scope.$watch()
que cubriré más adelante en este texto.
En los puntos clave de su aplicación, AngularJS llama a la función $scope.$digest()
. Esta función recorre todos los controles y verifica si alguna de las variables observadas ha cambiado. Si una variable observada ha cambiado, se llama a la función de escucha correspondiente. La función de escucha hace el trabajo que necesita hacer, por ejemplo, cambiar un texto HTML para reflejar el nuevo valor de la variable observada. Por lo tanto, la función $digest()
es lo que activa el enlace de datos para actualizar.
La mayoría de las veces, AngularJS llamará a las funciones $ scope. $ Watch () y $scope.$digest()
, pero en algunas situaciones es posible que tenga que llamarlas usted mismo. Por lo tanto, es realmente bueno saber cómo funcionan.
La función $scope.$apply()
se utiliza para ejecutar algún código y, a continuación, llama a $scope.$digest()
después de eso, por lo que se verifican todos los controles y se activan las funciones de escucha correspondientes. La función $apply()
es útil cuando se integra AngularJS con otro código.
Voy a entrar en más detalles sobre las funciones $watch(), $digest()
y $apply()
en el resto de este texto.
$ reloj ()
La función $scope.watch()
crea una observación de alguna variable. Cuando registra un reloj, pasa dos funciones como parámetros a la función $watch()
:
- Una función de valor
- Una función de escucha
Aquí hay un ejemplo:
$scope.$watch(function() {},
function() {}
);
La primera función es la función de valor y la segunda función es la función de escucha.
La función de valor debe devolver el valor que se está observando. AngularJS puede verificar el valor devuelto contra el valor que la función de vigilancia devolvió la última vez. De esa manera, AngularJS puede determinar si el valor ha cambiado. Aquí hay un ejemplo:
$scope.$watch(function(scope) { return scope.data.myVar },
function() {}
);
Esta función valule de ejemplo devuelve la variable $scope
scope.data.myVar
. Si el valor de esta variable cambia, se devolverá un valor diferente y AngularJS llamará a la función de escucha.
Observe cómo la función de valor toma el alcance como parámetro (sin el $ en el nombre). A través de este parámetro, la función de valor puede acceder al $scope
y sus variables. La función de valor también puede observar las variables globales si lo necesita, pero la mayoría de las veces verá una variable de $scope
.
La función de escucha debe hacer lo que sea necesario si el valor ha cambiado. Tal vez necesite cambiar el contenido de otra variable o configurar el contenido de un elemento HTML o algo así. Aquí hay un ejemplo:
$scope.$watch(function(scope) { return scope.data.myVar },
function(newValue, oldValue) {
document.getElementById("").innerHTML =
"" + newValue + "";
}
);
Este ejemplo establece el HTML interno de un elemento HTML al nuevo valor de la variable, incrustado en el elemento b, que hace que el valor esté en negrita. Por supuesto, podría haber hecho esto usando el código {{ data.myVar }
, pero esto es solo un ejemplo de lo que puede hacer dentro de la función de escucha.
$ digerir ()
La función $scope.$digest()
itera a través de todos los relojes en el $scope object
, y sus objetos secundarios $ scope (si tiene alguno). Cuando $digest()
itera sobre los relojes, llama a la función de valor para cada reloj. Si el valor devuelto por la función de valor es diferente al valor que devolvió la última vez que se llamó, se llama a la función de escucha para ese reloj.
La función $digest()
se llama siempre que AngularJS lo considere necesario. Por ejemplo, después de que se haya ejecutado un controlador de clic de botón, o después de que se devuelva una llamada AJAX
(después de que se haya ejecutado la función de devolución de llamada done () / fail ()).
Puede encontrar algunos casos de esquina en los que AngularJS no llama la función $digest()
por usted. Por lo general, lo detectará notando que los enlaces de datos no actualizan los valores mostrados. En ese caso, llame a $scope.$digest()
y debería funcionar. O, quizás pueda usar $scope.$apply()
lugar de lo que explicaré en la siguiente sección.
$ aplicar ()
La función $scope.$apply()
toma una función como parámetro que se ejecuta, y luego se llama internamente a $scope.$digest()
. Eso hace que sea más fácil para usted asegurarse de que todos los relojes estén marcados y, por lo tanto, de que se actualicen todos los enlaces de datos. Aquí hay un ejemplo de $apply()
:
$scope.$apply(function() {
$scope.data.myVar = "Another value";
});
La función pasada a la función $apply()
como parámetro cambiará el valor de $scope.data.myVar
. Cuando la función salga, AngularJS llamará a la función $scope.$digest()
para que todos los relojes se revisen en busca de cambios en los valores observados.
Ejemplo
Para ilustrar cómo funcionan $watch()
, $digest(
) y $apply()
, mira este ejemplo:
<div ng-controller="myController">
{{data.time}}
<br/>
<button ng-click="updateTime()">update time - ng-click</button>
<button id="updateTimeButton" >update time</button>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) {
$scope.data = { time : new Date() };
$scope.updateTime = function() {
$scope.data.time = new Date();
}
document.getElementById("updateTimeButton")
.addEventListener(''click'', function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
</script>
su ejemplo une la variable $scope.data.time
a una directiva de interpolación que combina el valor de la variable en la página HTML. Este enlace crea un reloj interno en la $scope.data.time variable
.
El ejemplo también contiene dos botones. El primer botón tiene un oyente conectado con un ng-click
. Cuando se hace clic en ese botón, se llama a la función $scope.updateTime()
y, a continuación, AngularJS llama a $scope.$digest()
para que se actualicen los enlaces de datos.
El segundo botón recibe un detector de eventos JavaScript estándar adjunto desde dentro de la función del controlador. Cuando se hace clic en el segundo botón, se ejecuta la función de escucha. Como puede ver, las funciones de escucha para ambos botones hacen casi lo mismo, pero cuando se llama a la función de escucha del segundo botón, el enlace de datos no se actualiza. Esto se debe a que $scope.$digest()
no se llama después de que se ejecuta el detector de eventos del segundo botón. Por lo tanto, si hace clic en el segundo botón, la hora se actualiza en la variable $scope.data.time
, pero la nueva hora nunca se muestra.
Para solucionarlo, podemos agregar una llamada a $scope.$digest()
a la última línea del detector de eventos de botón, como esto:
document.getElementById("updateTimeButton")
.addEventListener(''click'', function() {
console.log("update time clicked");
$scope.data.time = new Date();
$scope.$digest();
});
En lugar de llamar a $digest()
dentro de la función de escucha de botones, también podría haber usado la función $apply()
siguiente manera:
document.getElementById("updateTimeButton")
.addEventListener(''click'', function() {
$scope.$apply(function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
Observe cómo se llama a la función $scope.$apply()
desde el detector de eventos de botón, y cómo se realiza la actualización de la variable $scope.data.time
dentro de la función pasada como parámetro a la función $apply()
. Cuando la llamada a la función $apply()
finaliza, AngularJS llama a $digest()
internamente, por lo que todos los enlaces de datos se actualizan.