angularjs - example - directivas angular 5
¿Cómo funciona la detección de cambios Angular 2? (2)
En Angular 1, la detección de cambios se realizó mediante la comprobación de la jerarquía de $ scope. Implícitamente o explícitamente crearíamos observadores en nuestras plantillas, controladores o componentes.
En Angular 2 ya no tenemos $ scope, pero sí reemplazamos setInterval, setTimeout, et al. Puedo ver cómo Angular podría usar esto para desencadenar un resumen de $, pero ¿cómo determina Angular lo que ha cambiado, especialmente dado que Object.observe nunca llegó a los navegadores?
Ejemplo
Aquí hay un ejemplo simple. Un objeto definido en un servicio se actualiza en un setInterval. El DOM se recompila cada intervalo.
¿Cómo puede Angular saber que AppComponent está vigilando el servicio y que el valor de un atributo del servicio ha cambiado?
var InjectedService = function() {
var val = {a:1}
setInterval(() => val.a++, 1000);
return val;
}
var AppComponent = ng.core
.Component({
selector: "app",
template:
`
{{service.a}}
`
})
.Class({
constructor: function(service) {
this.service = service;
}
})
AppComponent.parameters = [ new ng.core.Inject( InjectedService ) ];
document.addEventListener(''DOMContentLoaded'', function() {
ng.platform.browser.bootstrap(AppComponent, [InjectedService])
});
Zone.js
Los cambios suceden como una reacción a algo, por lo que a este respecto son asíncronos. Son causadas por acciones asíncronas, y en el mundo del navegador son Events . Para interceptar esos eventos, angular usa zone.js , que parchea la pila de llamadas de JavaScript (creo, alguien me corrige si me equivoco) y expone los enganches que se pueden usar para realizar otras acciones.
function angular() {...}
zone.run(angular);
Si imaginas que esta función angular
es la Angular completa, así sería como se ejecuta en la zona. Al hacerlo, los eventos pueden ser interceptados y, si se activan, podemos asumir que los cambios suceden y escucharlos / observarlos.
AplicaciónRef
En realidad ApplicationRef
crea la zona:
/**
* Create an Angular zone.
*/
export function createNgZone(): NgZone {
return new NgZone({enableLongStackTrace: assertionsEnabled()});
}
y la clase NgZone
se crea con pocos emisores de eventos :
this._onTurnStartEvents = new EventEmitter(false);
this._onTurnDoneEvents = new EventEmitter(false);
this._onEventDoneEvents = new EventEmitter(false);
this._onErrorEvents = new EventEmitter(false);
que expone al mundo exterior a través de captadores:
get onTurnStart(): /* Subject */ any { return this._onTurnStartEvents; }
get onTurnDone() { return this._onTurnDoneEvents; }
get onEventDone() { return this._onEventDoneEvents; }
get onError() { return this._onErrorEvents; }
Cuando se created ApplicationRef
se suscribe a los eventos de la zona, específicamente onTurnDone()
:
this.zone.onTurnDone
.subscribe(() => this.zone.run(() => this.tick());
Cambios
Cuando se desencadenan eventos, se ejecuta la función tick()
que recorre cada componente:
this._changeDetectorRefs.forEach((detector) => detector.detectChanges());
y detecta cambios en función de la función ChangeDetectionStrategy
los componentes. Esos cambios se recopilan como una matriz de objetos SimpleChange
:
addChange(changes: {[key: string]: any}, oldValue: any, newValue: any): {[key: string]: any} {
if (isBlank(changes)) {
changes = {};
}
changes[this._currentBinding().name] = ChangeDetectionUtil.simpleChange(oldValue, newValue);
return changes;
}
witch está disponible para nosotros a través de la interfaz onChanges
:
export interface OnChanges {
ngOnChanges(changes: {[key: string]: SimpleChange});
}
Angular crea un objeto detector de cambio (ver ChangeDetectorRef ) por componente, que rastrea el último valor de cada enlace de plantilla, como {{service.a}}
. De forma predeterminada, después de cada evento de navegador asíncrono (como una respuesta de un servidor, un evento de clic o un evento de tiempo de espera), la detección de cambios angulares se ejecuta y verifica suciamente cada enlace que utiliza esos objetos detectores de cambios.
Si se detecta un cambio, el cambio se propaga. P.ej,
- Si un valor de propiedad de entrada cambia, el nuevo valor se propaga a la propiedad de entrada del componente.
- Si un valor de enlace
{{}}
cambia, el nuevo valor se propaga a la propiedad DOMtextContent
. - Si el valor de
x
cambia en un estilo, atributo o enlace de clase, es decir,[style.x]
o[attr.x]
o[class.x]
, el nuevo valor se propaga al DOM para actualizar el estilo, HTML atributo, o clase.
Angular usa Zone.js para crear su propia zona ( NgZone ), que parchea todos los eventos asíncronos (eventos DOM del navegador, tiempos de espera, AJAX / XHR). Así es como la detección de cambios puede ejecutarse automáticamente después de cada evento asíncrono. Es decir, después de que finalice cada manejador de eventos asíncronos (función), se ejecutará la detección de cambio angular.
Tengo muchos más detalles y enlaces de referencia en esta respuesta: ¿Cuál es el equivalente de Angular2 a un reloj AngularJS $?