¿Cómo funciona el enlace de datos en AngularJS?

1957

¿Cómo funciona el enlace de datos en el AngularJSmarco?

No he encontrado detalles técnicos en su sitio . Está más o menos claro cómo funciona cuando los datos se propagan de la vista al modelo. Pero, ¿cómo realiza AngularJS el seguimiento de los cambios en las propiedades del modelo sin establecedores y captadores?

Descubrí que hay observadores de JavaScript que pueden hacer este trabajo. Pero no son compatibles con Internet Explorer 6 e Internet Explorer 7 . Entonces, ¿cómo sabe AngularJS que cambié, por ejemplo, lo siguiente y reflejé este cambio en una vista?

myobject.myproperty="new value";
Pashec
fuente
10
Tenga en cuenta que desde angular 1.0.0rc1 necesita especificar ng-model-instant ( docs-next.angularjs.org/api/… ) para que su moderador se actualice de manera instantánea. De lo contrario, se actualizará en caso de desenfoque.
Sotomajor
8
El enlace de Marcello aparentemente está roto, así que aquí está de nuevo: github.com/mhevery/angular.js/blob/master/docs/content/guide/…
riffraff
66
@orian, ese enlace es malo. actualizado a (supongo) es lo mismo - docs.angularjs.org/guide/databinding
Kevin Meredith
11
Para aquellos que aún leen esta pregunta, tenga en cuenta que Angular 2.0 ha cambiado mucho la forma en que se vinculan los datos desde Angular 1.x para trabajar con componentes web y abordar muchos de los problemas en las respuestas a continuación.
agosto

Respuestas:

2745

AngularJS recuerda el valor y lo compara con un valor anterior. Esta es la comprobación básica de suciedad. Si hay un cambio en el valor, se activa el evento de cambio.

El $apply()método, que es lo que llamas cuando estás haciendo la transición de un mundo no AngularJS a un mundo AngularJS, llama $digest(). Un resumen es simplemente una vieja verificación sucia. Funciona en todos los navegadores y es totalmente predecible.

Para contrastar la verificación sucia (AngularJS) frente a los oyentes de cambio ( KnockoutJS y Backbone.js ): Si bien la verificación sucia puede parecer simple e incluso ineficiente (lo abordaré más adelante), resulta que es semánticamente correcto todo el tiempo, mientras que los oyentes de cambios tienen muchos casos extraños en las esquinas y necesitan cosas como el seguimiento de dependencias para hacerlo más semánticamente correcto. El seguimiento de dependencia de KnockoutJS es una característica inteligente para un problema que AngularJS no tiene.

Problemas con los oyentes de cambio:

  • La sintaxis es atroz, ya que los navegadores no la admiten de forma nativa. Sí, hay proxies, pero no son semánticamente correctos en todos los casos y, por supuesto, no hay proxies en los navegadores antiguos. La conclusión es que la verificación sucia le permite hacer POJO , mientras que KnockoutJS y Backbone.js lo obligan a heredar de sus clases y acceder a sus datos a través de los accesores.
  • Cambiar la fusión. Supongamos que tiene una variedad de artículos. Supongamos que desea agregar elementos a una matriz, ya que está haciendo un bucle para agregar, cada vez que agrega está activando eventos en el cambio, lo que representa la interfaz de usuario. Esto es muy malo para el rendimiento. Lo que desea es actualizar la IU solo una vez, al final. Los eventos de cambio son demasiado finos.
  • Los oyentes de cambio se disparan inmediatamente en un setter, lo cual es un problema, ya que el oyente de cambios puede cambiar aún más los datos, lo que dispara más eventos de cambio. Esto es malo, ya que en su pila puede tener varios eventos de cambio sucediendo a la vez. Supongamos que tiene dos matrices que deben mantenerse sincronizadas por cualquier motivo. Solo puede agregar a uno u otro, pero cada vez que agrega dispara un evento de cambio, que ahora tiene una visión inconsistente del mundo. Este es un problema muy similar al bloqueo de hilos, que JavaScript evita ya que cada devolución de llamada se ejecuta exclusivamente y hasta su finalización. Los eventos de cambio rompen esto, ya que los establecedores pueden tener consecuencias de largo alcance que no son intencionadas y no son obvias, lo que crea el problema del hilo nuevamente. Resulta que lo que quieres hacer es retrasar la ejecución del oyente y garantizar,

¿Qué pasa con el rendimiento?

Por lo tanto, puede parecer que somos lentos, ya que la verificación sucia es ineficiente. Aquí es donde debemos mirar los números reales en lugar de solo tener argumentos teóricos, pero primero definamos algunas restricciones.

Los humanos son:

  • Lento : cualquier cosa que supere los 50 ms es imperceptible para los humanos y, por lo tanto, puede considerarse "instantáneo".

  • Limitado : en realidad, no puede mostrar más de aproximadamente 2000 piezas de información a un humano en una sola página. Cualquier cosa más que eso es una interfaz de usuario realmente mala, y los humanos no pueden procesar esto de todos modos.

Entonces, la verdadera pregunta es esta: ¿Cuántas comparaciones puede hacer en un navegador en 50 ms? Esta es una pregunta difícil de responder ya que muchos factores entran en juego, pero aquí hay un caso de prueba: http://jsperf.com/angularjs-digest/6 que crea 10,000 observadores. En un navegador moderno, esto lleva menos de 6 ms. En Internet Explorer 8 tarda unos 40 ms. Como puede ver, esto no es un problema, incluso en navegadores lentos en estos días. Hay una advertencia: las comparaciones deben ser simples para ajustarse al límite de tiempo ... Desafortunadamente, es demasiado fácil agregar una comparación lenta en AngularJS, por lo que es fácil crear aplicaciones lentas cuando no sabes lo que estás haciendo. Pero esperamos tener una respuesta al proporcionar un módulo de instrumentación, que le mostrará cuáles son las comparaciones lentas.

Resulta que los videojuegos y las GPU utilizan el enfoque de verificación sucia, específicamente porque es consistente. Siempre que superen la frecuencia de actualización del monitor (generalmente 50-60 Hz, o cada 16.6-20 ms), cualquier rendimiento por encima de eso es un desperdicio, por lo que es mejor dibujar más cosas, que aumentar el FPS.

Misko Hevery
fuente
32
@Mark: sí, en KO solo agrega .extend ({throttle: 500}) para esperar 500 milisegundos después del último evento de cambio antes de actuar sobre él.
Daniel Earwicker
158
Esta respuesta completa es excelente además de "Siempre y cuando obtengan 50 fps, cualquier rendimiento por encima de eso es un desperdicio, ya que el ojo humano no puede apreciarlo, por lo que es mejor dibujar más cosas, que obtener fps más alto". Esa declaración es completamente incorrecta dependiendo de su aplicación. El ojo definitivamente puede apreciar más de 50 fps, y como muestran los diversos problemas con la realidad virtual (lea cualquiera de los últimos de John Carmack o Michael Abrash, especialmente la charla de realidad virtual GDC 2013 de este último), 50 fps es realmente demasiado lento. Aparte de eso, tu respuesta es genial. Simplemente no quiero que se difunda la información errónea.
Nate Bundy
10
@DavidRivers us es µs como en utorrent 1µs = 0.000001s
Thorgeir
33
La afirmación podría decirse fácilmente a la inversa como "La comprobación sucia es una característica inteligente para un problema que no tiene la eliminación". ES6 está utilizando observables y angular se está deshaciendo de la comprobación sucia. El mundo real alcanzó esta respuesta y demostró que era falsa.
cónico
17
"Cualquier cosa más rápido que 50 ms es imperceptible para los humanos" no es cierto. En las pruebas, hemos descubierto que nuestros clientes pueden distinguir fácilmente entre una latencia de actualización de 50 ms (20 fps) y una latencia de actualización de 16,6 ms (60 fps). Las escenas que se ejecutan a la velocidad anterior son cada vez más bajas en las calificaciones generales de "cómo se sintió", incluso cuando las personas no registraron conscientemente la velocidad de fotogramas.
Crashworks
323

Misko ya dio una excelente descripción de cómo funcionan los enlaces de datos, pero me gustaría agregar mi opinión sobre el problema de rendimiento con el enlace de datos.

Como dijo Misko, alrededor de 2000 enlaces es donde comienzas a ver problemas, pero de todos modos no debes tener más de 2000 datos en una página. Esto puede ser cierto, pero no todos los enlaces de datos son visibles para el usuario. Una vez que comience a construir cualquier tipo de widget o cuadrícula de datos con enlace bidireccional, puede alcanzar fácilmente 2000 enlaces, sin tener una mala experiencia de usuario.

Considere, por ejemplo, un cuadro combinado donde puede escribir texto para filtrar las opciones disponibles. Este tipo de control podría tener ~ 150 elementos y aún ser altamente utilizable. Si tiene alguna característica adicional (por ejemplo, una clase específica en la opción seleccionada actualmente), comienza a obtener 3-5 enlaces por opción. Coloque tres de estos widgets en una página (por ejemplo, uno para seleccionar un país, el otro para seleccionar una ciudad en dicho país y el tercero para seleccionar un hotel) y ya se encuentra entre 1000 y 2000 enlaces.

O considere una cuadrícula de datos en una aplicación web corporativa. 50 filas por página no son irrazonables, cada una de las cuales podría tener 10-20 columnas. Si construye esto con ng-repeats, y / o tiene información en algunas celdas que usa algunos enlaces, podría acercarse a 2000 enlaces solo con esta cuadrícula.

Creo que esto es un gran problema cuando trabajo con AngularJS, y la única solución que he podido encontrar hasta ahora es construir widgets sin usar enlace bidireccional, en lugar de usar ngOnce, cancelar el registro de observadores y trucos similares, o construir directivas que construyen el DOM con jQuery y la manipulación del DOM. Siento que esto derrota el propósito de usar Angular en primer lugar.

Me encantaría escuchar sugerencias sobre otras formas de manejar esto, pero tal vez debería escribir mi propia pregunta. Quería poner esto en un comentario, pero resultó ser demasiado largo para eso ...

TL; DR
El enlace de datos puede causar problemas de rendimiento en páginas complejas.

MW.
fuente
26
Sí, secundo esto. La responsabilidad principal de nuestra aplicación es mostrar las conexiones entre diferentes entidades. Una página dada puede tener 10 secciones. Cada sección tiene una mesa. Cada tabla tiene 2-5 filtros de escritura anticipada. Cada tabla tiene 2-5 columnas, cada una con 10 filas. Muy rápidamente nos encontramos con problemas de rendimiento y vamos con las opciones de "trucos similares".
Scott Silvi
10
¿Es justo decir que Angular no se trata solo del enlace de datos y que algunas aplicaciones pueden no querer usar esta función exactamente por las razones que otros han citado? Creo que el enfoque de DI y la modularidad en sí vale mucho; tener un enlace automático mágico es bueno, pero en cada implementación existente tiene compensaciones de rendimiento. La forma de Angular es posiblemente superior para la mayoría de las aplicaciones web CRUD, y las personas simplemente están golpeando un muro al tratar de llevarlo a los extremos. Sería bueno tener un método alternativo de escucha de eventos compatible, pero ¿tal vez eso es fundamentalmente demasiado complejo para un solo marco?
Jason Boyd
8
Angular ahora tiene un enlace de datos unidireccional y de enlace único para ayudar con este problema. Además, ahora tiene índices para su fuente de repetidor, lo que le permite modificar la lista sin reconstruir el dom para todo el contenido.
Gaute Løken
66
@MW. Honestamente, pensé que bind-once estaba en el centro. Pero parece que no lo es. Es algo que puedes hacer al escribir tus propias directivas, básicamente vinculando cosas sin mirarlas. Sin embargo, hay un mod de UX
Gaute Løken
99
Un grito del futuro para cualquiera que lea esto: un enlace único ahora es una característica central en Angular v1.3, lea más aquí: docs.angularjs.org/guide/expression
Nobita
158

Comprobando sucio el $scopeobjeto

Angular mantiene un simple arrayobservador en los $scopeobjetos. Si inspecciona alguno $scope, encontrará que contiene un arrayllamado $$watchers.

Cada observador es un objectque contiene entre otras cosas

  1. Una expresión que el observador está monitoreando. Esto podría ser solo un attributenombre, o algo más complicado.
  2. Un último valor conocido de la expresión. Esto se puede verificar con el valor calculado actual de la expresión. Si los valores difieren, el observador activará la función y la marcará $scopecomo sucia.
  3. Una función que se ejecutará si el observador está sucio.

Cómo se definen los observadores

Hay muchas formas diferentes de definir un observador en AngularJS.

  • Puede explícitamente $watchun attributeencendido $scope.

    $scope.$watch('person.username', validateUnique);
  • Puede colocar una {{}}interpolación en su plantilla (se creará un observador para usted en la actual $scope).

    <p>username: {{person.username}}</p>
  • Puede solicitar una directiva como la ng-modelque define al observador por usted.

    <input ng-model="person.username" />

El $digestciclo verifica a todos los observadores contra su último valor

Cuando interactuamos con AngularJS a través de los canales normales (ng-model, ng-repeat, etc.) la directiva activará un ciclo de resumen.

Un ciclo de digestión es un recorrido profundo y primero de $scopetodos sus hijos . Para cada uno $scope object, iteramos sobre él $$watchers arrayy evaluamos todas las expresiones. Si el nuevo valor de expresión es diferente del último valor conocido, se llama a la función del observador. Esta función podría recompilar parte del DOM, recalcular un valor $scope, activar un AJAX request, cualquier cosa que necesite hacer.

Se recorre cada ámbito y cada expresión de observación se evalúa y se compara con el último valor.

Si se activa un observador, $scopeestá sucio

Si se activa un observador, la aplicación sabe que algo ha cambiado y $scopeestá marcado como sucio.

Las funciones de vigilante pueden cambiar otros atributos en $scopeo en un padre $scope. Si se $watcherha activado una función, no podemos garantizar que nuestras otras $scopeestén todavía limpias, por lo que ejecutamos todo el ciclo de resumen nuevamente.

Esto se debe a que AngularJS tiene un enlace bidireccional, por lo que los datos se pueden volver a pasar al $scopeárbol. Podemos cambiar un valor en un valor superior $scopeque ya ha sido digerido. Quizás cambiemos un valor en el $rootScope.

Si $digestestá sucio, ejecutamos todo el $digestciclo nuevamente

Continuamente recorremos el $digestciclo hasta que el ciclo de resumen salga limpio (todas las $watchexpresiones tienen el mismo valor que tenían en el ciclo anterior) o alcanzamos el límite de resumen. Por defecto, este límite se establece en 10.

Si alcanzamos el límite de resumen, AngularJS generará un error en la consola:

10 $digest() iterations reached. Aborting!

El resumen es difícil para la máquina pero fácil para el desarrollador

Como puede ver, cada vez que algo cambia en una aplicación AngularJS, AngularJS verificará a cada observador en la $scopejerarquía para ver cómo responder. Para un desarrollador, esto es una gran ayuda para la productividad, ya que ahora necesita escribir casi ningún código de cableado, AngularJS solo notará si un valor ha cambiado y hará que el resto de la aplicación sea consistente con el cambio.

Desde la perspectiva de la máquina, aunque esto es muy ineficiente y ralentizará nuestra aplicación si creamos demasiados observadores. Misko ha citado una cifra de aproximadamente 4000 observadores antes de que su aplicación parezca lenta en navegadores antiguos.

Este límite es fácil de alcanzar si ng-repeatsupera un gran, JSON arraypor ejemplo. Puede mitigar esto usando características como el enlace único para compilar una plantilla sin crear observadores.

Cómo evitar crear demasiados observadores

Cada vez que su usuario interactúa con su aplicación, cada observador en su aplicación será evaluado al menos una vez. Una gran parte de la optimización de una aplicación AngularJS es reducir la cantidad de observadores en su $scopeárbol. Una manera fácil de hacer esto es con un enlace único .

Si tiene datos que rara vez cambiarán, puede vincularlos solo una vez usando la sintaxis ::, así:

<p>{{::person.username}}</p>

o

<p ng-bind="::person.username"></p>

El enlace solo se activará cuando se represente la plantilla que contiene y se carguen los datos $scope.

Esto es especialmente importante cuando tienes ng-repeatmuchos artículos.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>
superluminario
fuente
Gracias @ user2864740, aunque es correcto que la respuesta de Misko sea la mejor. Él conoce el marco mejor que nadie, y es genial que se involucre con Stack Overflow ..
superluminary
44
No estoy de acuerdo con que dicha respuesta debería estar en la parte superior; Hay una diferencia entre saber algo y escribir una respuesta relevante / detallada para una pregunta específica. Hay mejores formas de obtener elogios. De todos modos ..
user2864740
1
No dudo que eso sea cierto, pero preguntas preguntas y respuestas respuestas :)
user2864740
3
Buena respuesta que cubre cómo se comporta el cheque sucio y lo que realmente está evaluando, una cosa no estaba demasiado clara en la respuesta de Misko.
Strider
3
Excelente y detallada respuesta. @superluminary, gracias por tal respuesta. Además, después de leer esta respuesta, llego al punto de que no debemos agregar una expresión no idempotente como una expresión que se está observando.
Mangu Singh Rajpurohit 01 de
81

Este es mi entendimiento básico. ¡Bien puede estar mal!

  1. Los elementos se miran pasando una función (devolviendo lo que se va a ver) al $watchmétodo.
  2. Los cambios en los elementos observados deben realizarse dentro de un bloque de código envuelto por el $applymétodo.
  3. Al final de la $applydel $digestmétodo se invoca el cual pasa a través de cada uno de los relojes y controles para ver si han cambiado desde la última vez que el $digestRAN.
  4. Si se encuentran cambios, el resumen se invoca nuevamente hasta que todos los cambios se estabilicen.

En el desarrollo normal, la sintaxis de enlace de datos en el HTML le dice al compilador AngularJS que cree los relojes para usted y los métodos del controlador ya se ejecutan dentro $apply. Entonces, para el desarrollador de la aplicación, todo es transparente.

Pete BD
fuente
44
¿Cuándo se activa el método de aplicación?
numan salati
3
@EliseuMonar El ciclo de resumen se ejecuta como resultado de algún evento o llamando a $ apply (), no se llama periódicamente en función de un temporizador. ver ¿Cómo funciona la función $ watch de AngularJS? ¿
adl
1
@remi, no me preocupa la última versión de AngularJS. ¿Ya están usando proxies o Object.observe? De lo contrario, todavía están en la era de la verificación sucia, que crea un bucle temporizado para ver si los atributos del modelo han cambiado.
Eliseu Monar dos Santos
1
He leído que el resumen se ejecutará un máximo de diez veces sitepoint.com/understanding-angulars-apply-digest
user137717
62

Me lo pregunté por un tiempo. Sin setters, ¿cómo se AngularJSnotan los cambios en el $scopeobjeto? ¿Los encuesta?

Lo que en realidad hace es esto: cualquier lugar "normal" en el que modifique el modelo ya fue llamado desde el interior de AngularJS, por lo que automáticamente lo llamará $applydespués de que se ejecute su código. Digamos que su controlador tiene un método conectado a ng-clickalgún elemento. Debido a que AngularJSconecta la llamada de ese método para usted, tiene la oportunidad de hacerlo $applyen el lugar apropiado. Del mismo modo, para las expresiones que aparecen justo en las vistas, se ejecutan por AngularJSlo que hace el $apply.

Cuando la documentación habla de tener que llamar $applymanualmente para obtener un código externoAngularJS , se trata de un código que, cuando se ejecuta, no proviene de AngularJSsí mismo en la pila de llamadas.

jpsimons
fuente
32

Explicando con fotos:

El enlace de datos necesita un mapeo

La referencia en el alcance no es exactamente la referencia en la plantilla. Cuando vincula dos objetos a datos, necesita un tercero que escuche el primero y modifique el otro.

ingrese la descripción de la imagen aquí

Aquí, cuando modifica el <input>, toca el data-ref3 . Y el mecanismo clásico de enlace de datos cambiará data-ref4 . Entonces, ¿cómo {{data}}se moverán las otras expresiones?

Los eventos conducen a $ digest ()

ingrese la descripción de la imagen aquí

Angular mantiene un oldValuey newValuede cada enlace. Y después de cada evento angular , el famoso $digest()bucle verificará la WatchList para ver si algo cambió. Estos eventos angular son ng-click, ng-change, $httpcompletada ... El $digest()bucle de voluntad, siempre y cuando ningún oldValuedifiere de la newValue.

En la imagen anterior, notará que data-ref1 y data-ref2 ha cambiado.

Conclusiones

Es un poco como el huevo y el pollo. Nunca se sabe quién comienza, pero espero que funcione la mayor parte del tiempo como se esperaba.

El otro punto es que puede comprender fácilmente el impacto profundo de un enlace simple en la memoria y la CPU. Esperemos que las computadoras de escritorio sean lo suficientemente gordas para manejar esto. Los teléfonos móviles no son tan fuertes.

Nicolas Zozol
fuente
22

Obviamente, no hay una comprobación periódica de Scopesi hay algún cambio en los objetos adjuntos. No se miran todos los objetos adjuntos al alcance. Alcance prototípicamente mantiene un $$ observadores . Scopesolo itera a través de esto $$watcherscuando $digestse llama.

Angular agrega un observador a los observadores $$ para cada uno de estos

  1. {{expresión}}: en sus plantillas (y en cualquier otro lugar donde haya una expresión) o cuando definimos ng-model.
  2. $ scope. $ watch ('expresión / función'): en su JavaScript solo podemos adjuntar un objeto de alcance para que angular lo vea.

La función $ watch toma tres parámetros:

  1. La primera es una función de observador que simplemente devuelve el objeto o simplemente podemos agregar una expresión.

  2. La segunda es una función de escucha que se llamará cuando haya un cambio en el objeto. Todas las cosas como los cambios DOM se implementarán en esta función.

  3. El tercero es un parámetro opcional que toma un valor booleano. Si es cierto, angular profundo observa el objeto y si es falso Angular solo hace una observación de referencia en el objeto. La implementación aproximada de $ watch se ve así

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

Hay una cosa interesante en Angular llamada Digest Cycle. El ciclo de $ digest comienza como resultado de una llamada a $ scope. $ Digest (). Suponga que cambia un modelo $ scope en una función de controlador a través de la directiva ng-click. En ese caso, AngularJS activa automáticamente un ciclo de $ digest llamando a $ digest (). Además de ng-click, hay varias otras directivas / servicios integrados que le permiten cambiar los modelos (por ejemplo, ng-model, $ timeout, etc.) y activa automáticamente un ciclo de $ digest. La implementación aproximada de $ digest se ve así.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

Si utilizamos la función setTimeout () de JavaScript para actualizar un modelo de alcance, Angular no tiene forma de saber qué puede cambiar. En este caso, es nuestra responsabilidad llamar a $ apply () manualmente, lo que desencadena un ciclo de $ digest. Del mismo modo, si tiene una directiva que configura un detector de eventos DOM y cambia algunos modelos dentro de la función del controlador, debe llamar a $ apply () para garantizar que los cambios surtan efecto. La gran idea de $ apply es que podemos ejecutar algún código que no tenga conocimiento de Angular, ese código aún puede cambiar las cosas en el alcance. Si ajustamos ese código en $ apply, se encargará de llamar a $ digest (). Implementación aproximada de $ apply ().

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};
Sasank Sunkavalli
fuente
15

AngularJS maneja el mecanismo de enlace de datos con la ayuda de tres potentes funciones: $ watch () , $ digest () y $ apply () . La mayoría de las veces, AngularJS llamará a $ scope. $ Watch () y $ scope. $ Digest (), pero en algunos casos puede que tenga que llamar a estas funciones manualmente para actualizar con nuevos valores.

$ reloj () : -

Esta función se utiliza para observar cambios en una variable en el ámbito $. Acepta tres parámetros: expresión, escucha y objeto de igualdad, donde escucha y objeto de igualdad son parámetros opcionales.

$ digest () -

Esta función itera a través de todos los relojes en el objeto $ scope y sus objetos secundarios $ scope
(si tiene alguno). Cuando $ digest () itera sobre los relojes, comprueba si el valor de la expresión ha cambiado. Si el valor ha cambiado, AngularJS llama al oyente con un nuevo valor y un valor antiguo. La función $ digest () se llama cuando AngularJS cree que es necesario. Por ejemplo, después de hacer clic en un botón o después de una llamada AJAX. Es posible que tenga algunos casos en los que AngularJS no llame a la función $ digest () por usted. En ese caso, debe llamarlo usted mismo.

$ apply () -

Angular do actualiza automáticamente mágicamente solo aquellos cambios de modelo que están dentro del contexto de AngularJS. Cuando cambia en cualquier modelo fuera del contexto angular (como los eventos DOM del navegador, setTimeout, XHR o bibliotecas de terceros), debe informar a Angular de los cambios llamando a $ apply () manualmente. Cuando la llamada a la función $ apply () finaliza, AngularJS llama a $ digest () internamente, por lo que se actualizan todos los enlaces de datos.

Bharat Kumar
fuente
7

Sucedió que necesitaba vincular un modelo de datos de una persona con un formulario, lo que hice fue un mapeo directo de los datos con el formulario.

Por ejemplo, si el modelo tenía algo como:

$scope.model.people.name

La entrada de control del formulario:

<input type="text" name="namePeople" model="model.people.name">

De esa manera, si modifica el valor del controlador de objetos, esto se reflejará automáticamente en la vista.

Un ejemplo en el que pasé el modelo se actualiza a partir de los datos del servidor es cuando solicita un código postal y un código postal basado en cargas escritas, una lista de colonias y ciudades asociadas con esa vista y, de forma predeterminada, establece el primer valor con el usuario. Y esto funcionó muy bien, lo que sucede es que a angularJSveces lleva unos segundos actualizar el modelo, para hacer esto puedes poner una rueda giratoria mientras se muestran los datos.

gartox
fuente
14
Leí esta respuesta 5 veces y todavía no entiendo lo que significa aquí.
sbedulin
1
Respuesta parece como rompecabezas para mí
Aman
6
  1. El enlace de datos unidireccional es un enfoque en el que se toma un valor del modelo de datos y se inserta en un elemento HTML. No hay forma de actualizar el modelo desde la vista. Se utiliza en sistemas de plantillas clásicas. Estos sistemas enlazan datos en una sola dirección.

  2. La vinculación de datos en aplicaciones angulares es la sincronización automática de datos entre el modelo y los componentes de la vista.

El enlace de datos le permite tratar el modelo como la única fuente de verdad en su aplicación. La vista es una proyección del modelo en todo momento. Si se cambia el modelo, la vista refleja el cambio y viceversa.

Shankar Gangadhar
fuente
5

Aquí hay un ejemplo de enlace de datos con AngularJS, utilizando un campo de entrada. Explicaré mas tarde

código HTML

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

Código AngularJS

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

Como puede ver en el ejemplo anterior, AngularJS utiliza ng-modelpara escuchar y ver lo que sucede en los elementos HTML, especialmente en los inputcampos. Cuando algo sucede, haz algo. En nuestro caso, ng-modelse une a nuestra vista, utilizando la notación de bigote {{}}. Lo que se escriba dentro del campo de entrada se muestra en la pantalla al instante. Y esa es la belleza del enlace de datos, usando AngularJS en su forma más simple.

Espero que esto ayude.

Vea un ejemplo de trabajo aquí en Codepen

AllJs
fuente
5

AngularJs admite enlace de datos bidireccional .
Significa que puede acceder a la vista de datos -> Controlador y controlador -> Ver

Por ej.

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

Puede vincular datos en ng-modelMe gusta: -
2)

<input ng-model="name" />

<div> {{ name }} </div>

Aquí, en el ejemplo anterior, cualquier entrada que dé el usuario, será visible en la <div>etiqueta.

Si desea vincular la entrada de html al controlador: -
3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

Aquí, si desea utilizar la entrada nameen el controlador, entonces,

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-modelune nuestro punto de vista y lo expresa en expresión {{ }}.
ng-modelson los datos que se muestran al usuario en la vista y con los que el usuario interactúa.
Por lo tanto, es fácil vincular datos en AngularJs.

ojus kulkarni
fuente
4

Angular.js crea un observador para cada modelo que creamos a la vista. Cada vez que se cambia un modelo, se agrega una clase "ng-dirty" al modelo, por lo que el observador observará todos los modelos que tengan la clase "ng-dirty" y actualizará sus valores en el controlador y viceversa.

Shankar Gangadhar
fuente
3

el enlace de datos:

¿Qué es el enlace de datos?

Cada vez que el usuario cambia los datos en la vista, se produce una actualización de ese cambio en el modelo de alcance, y viceversa.

¿Como es posible?

Respuesta corta: con la ayuda del ciclo de digestión.

Descripción: Angular js establece el observador en el modelo de alcance, que activa la función de escucha si hay un cambio en el modelo.

$scope.$watch('modelVar' , function(newValue,oldValue){

// Código de actualización Dom con nuevo valor

});

Entonces, ¿cuándo y cómo se llama la función de observador?

La función de vigilante se llama como parte del ciclo de resumen.

El ciclo de resumen se llama activado automáticamente como parte de js angulares integrados en directivas / servicios como ng-model, ng-bind, $ timeout, ng-click y otros ... que le permiten activar el ciclo de resumen.

Función del ciclo digestivo:

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

es decir$rootScope.$apply()

Nota: $ apply () es igual a $ rootScope. $ Digest () esto significa que la comprobación sucia comienza desde la raíz o la parte superior o el ámbito primario hasta todos los $ scopes secundarios en la aplicación angular js.

Las características anteriores funcionan en los navegadores IE para las versiones mencionadas también simplemente asegurándose de que su aplicación sea angular js, lo que significa que está utilizando el archivo de script de framework angularjs al que se hace referencia en la etiqueta del script.

Gracias.

Dhana
fuente