navigationend - title angular 6
¿Cuál es el equivalente angular de un reloj AngularJS $? (8)
En AngularJS, pudo especificar observadores para observar los cambios en las variables de alcance utilizando la función
$watch
de
$scope
.
¿Cuál es el equivalente de observar cambios variables (en, por ejemplo, variables componentes) en Angular?
Aquí hay otro enfoque que utiliza las funciones getter y setter para el modelo.
@Component({
selector: ''input-language'',
template: `
…
<input
type="text"
placeholder="Language"
[(ngModel)]="query"
/>
`,
})
export class InputLanguageComponent {
set query(value) {
this._query = value;
console.log(''query set to :'', value)
}
get query() {
return this._query;
}
}
En Angular 2, la detección de cambios es automática ...
$scope.$watch()
y
$scope.$digest()
RIP
Desafortunadamente, la sección Detección de cambios de la guía de desarrollo aún no está escrita (hay un marcador de posición cerca de la parte inferior de la página Descripción general de la arquitectura , en la sección "Otras cosas").
Aquí está mi comprensión de cómo funciona la detección de cambios:
-
Zone.js "monkey parches the world": intercepta todas las API asincrónicas en el navegador (cuando se ejecuta Angular).
Es por eso que podemos usar
setTimeout()
dentro de nuestros componentes en lugar de algo como$timeout
... porquesetTimeout()
tiene parches de mono. -
Angular construye y mantiene un árbol de "detectores de cambio".
Hay uno de estos detectores de cambio (clase) por componente / directiva.
(Puede obtener acceso a este objeto inyectando
ChangeDetectorRef
). Estos detectores de cambio se crean cuando Angular crea componentes. Realizan un seguimiento del estado de todas sus vinculaciones, para verificar sucias. Estos son, en cierto sentido, similares a los$watches()
automáticos que Angular 1 configuraría para los enlaces de plantilla{{}}
.
A diferencia de Angular 1, el gráfico de detección de cambios es un árbol dirigido y no puede tener ciclos (esto hace que Angular 2 sea mucho más eficiente, como veremos a continuación). - Cuando se dispara un evento (dentro de la zona angular), se ejecuta el código que escribimos (la devolución de llamada del controlador de eventos). Puede actualizar cualquier dato que desee: el modelo / estado de la aplicación compartida y / o el estado de vista del componente.
-
Después de eso, debido a los ganchos que Zone.js agregó, luego ejecuta el algoritmo de detección de cambios de Angular.
De forma predeterminada (es decir, si no está utilizando la estrategia de detección de cambios
onPush
en ninguno de sus componentes), cada componente del árbol se examina una vez (TTL = 1) ... desde la parte superior, en primer orden de profundidad. (Bueno, si está en modo dev, la detección de cambios se ejecuta dos veces (TTL = 2). Consulte ApplicationRef.tick() para obtener más información al respecto). Realiza una comprobación sucia de todos sus enlaces, utilizando esos objetos detectores de cambio.-
Los ganchos de ciclo de vida se llaman como parte de la detección de cambios.
Si los datos del componente que desea ver son una propiedad de entrada primitiva (String, boolean, number), puede implementarngOnChanges()
para recibir notificaciones de cambios.
Si la propiedad de entrada es un tipo de referencia (objeto, matriz, etc.), pero la referencia no cambió (por ejemplo, agregó un elemento a una matriz existente), deberá implementarngDoCheck()
(consulte esto responde por más sobre esto).
Solo debe cambiar las propiedades del componente y / o las propiedades de los componentes descendientes (debido a la implementación de un solo recorrido del árbol, es decir, el flujo de datos unidireccional). Aquí hay un saqueador que viola eso. Las tuberías con estado también pueden hacerte tropezar aquí.
-
Los ganchos de ciclo de vida se llaman como parte de la detección de cambios.
- Para cualquier cambio de enlace que se encuentre, los Componentes se actualizan y luego se actualiza el DOM. La detección de cambios ha finalizado.
- El navegador nota que el DOM cambia y actualiza la pantalla.
Otras referencias para aprender más:
- $ Digest de Angular renace en la versión más reciente de Angular : explica cómo las ideas de AngularJS se asignan a Angular
- Todo lo que necesita saber sobre la detección de cambios en Angular : explica con gran detalle cómo funciona la detección de cambios bajo el capó
- Explicación de la detección de cambios - Blog de Thoughtram 22 de febrero de 2016 - probablemente la mejor referencia disponible
- Video de Savkin''s Change Detection Reinvented - definitivamente mira este
- ¿Cómo funciona realmente la detección de cambios de Angular 2? - blog de jhade 24 de febrero de 2016
-
El video de Brian y el video de
Miško
sobre Zone.js.
Brian trata sobre Zone.js.
Miško trata sobre cómo Angular 2 usa Zone.js para implementar la detección de cambios.
También habla sobre la detección de cambios en general, y un poco sobre
onPush
. - Publicaciones del blog de Victor Savkins: Detección de cambios en Angular 2 , dos fases de aplicaciones Angular 2 , Angular, Inmutabilidad y Encapsulación . Cubre mucho terreno rápidamente, pero puede ser conciso a veces, y te quedas rascándote la cabeza, preguntándote por las piezas que faltan.
- Detección de cambios ultrarrápida (documento de Google): muy técnica, muy concisa, pero describe / bosqueja las clases ChangeDetection que se crean como parte del árbol
Este comportamiento ahora es parte del ciclo de vida del componente.
Un componente puede implementar el método ngOnChanges en la interfaz OnChanges para obtener acceso a los cambios de entrada.
Ejemplo:
import {Component, Input, OnChanges} from ''angular2/core'';
@Component({
selector: ''hero-comp'',
templateUrl: ''app/components/hero-comp/hero-comp.html'',
styleUrls: [''app/components/hero-comp/hero-comp.css''],
providers: [],
directives: [],
pipes: [],
inputs:[''hero'', ''real'']
})
export class HeroComp implements OnChanges{
@Input() hero:Hero;
@Input() real:string;
constructor() {
}
ngOnChanges(changes) {
console.log(changes);
}
}
Esto no responde la pregunta directamente, pero en varias ocasiones he llegado a esta pregunta de desbordamiento de pila para resolver algo que usaría $ watch en angularJs. Terminé usando un enfoque diferente al descrito en las respuestas actuales, y quiero compartirlo en caso de que alguien lo encuentre útil.
La técnica que uso para lograr algo similar
$watch
es usar un
BehaviorSubject
(
más sobre el tema aquí
) en un servicio Angular, y dejar que mis componentes se suscriban para obtener (ver) los cambios.
Esto es similar a un
$watch
en angularJs, pero requiere algo más de configuración y comprensión.
En mi componente:
export class HelloComponent {
name: string;
// inject our service, which holds the object we want to watch.
constructor(private helloService: HelloService){
// Here I am "watching" for changes by subscribing
this.helloService.getGreeting().subscribe( greeting => {
this.name = greeting.value;
});
}
}
En mi servicio
export class HelloService {
private helloSubject = new BehaviorSubject<{value: string}>({value: ''hello''});
constructor(){}
// similar to using $watch, in order to get updates of our object
getGreeting(): Observable<{value:string}> {
return this.helloSubject;
}
// Each time this method is called, each subscriber will receive the updated greeting.
setGreeting(greeting: string) {
this.helloSubject.next({value: greeting});
}
}
Aquí hay una demostración en Stackblitz
Pruebe esto cuando su aplicación
todavía
requiera
$parse
,
$eval
,
$watch
como comportamiento en Angular
Puede usar la
getter function
u
get accessor
para actuar como reloj en angular 2.
Ver demo here .
import {Component} from ''angular2/core'';
@Component({
// Declare the tag name in index.html to where the component attaches
selector: ''hello-world'',
// Location of the template for this component
template: `
<button (click)="OnPushArray1()">Push 1</button>
<div>
I''m array 1 {{ array1 | json }}
</div>
<button (click)="OnPushArray2()">Push 2</button>
<div>
I''m array 2 {{ array2 | json }}
</div>
I''m concatenated {{ concatenatedArray | json }}
<div>
I''m length of two arrays {{ arrayLength | json }}
</div>`
})
export class HelloWorld {
array1: any[] = [];
array2: any[] = [];
get concatenatedArray(): any[] {
return this.array1.concat(this.array2);
}
get arrayLength(): number {
return this.concatenatedArray.length;
}
OnPushArray1() {
this.array1.push(this.array1.length);
}
OnPushArray2() {
this.array2.push(this.array2.length);
}
}
Si desea que sea vinculante en 2 direcciones, puede usar
[(yourVar)]
, pero debe implementar
yourVarChange
evento
yourVarChange
y llamarlo cada vez que cambie su variable.
Algo como esto para seguir el cambio de héroe
@Output() heroChange = new EventEmitter();
y luego, cuando cambien su héroe, llame a
this.heroChange.emit(this.hero);
el enlace
[(hero)]
hará el resto por ti
ver ejemplo aquí:
Si, además del enlace bidireccional automático, desea llamar a una función cuando cambia un valor, puede romper la sintaxis de acceso directo del enlace bidireccional a la versión más detallada.
<input [(ngModel)]="yourVar"></input>
es una abreviatura de
<input [ngModel]="yourVar" (ngModelChange)="yourVar=$event"></input>
(véase, por ejemplo, http://victorsavkin.com/post/119943127151/angular-2-template-syntax )
Podrías hacer algo como esto:
<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>