Activación de la detección de cambios manualmente en angular

387

Estoy escribiendo un componente angular que tiene una propiedad Mode(): string .

Me gustaría poder establecer esta propiedad mediante programación no en respuesta a ningún evento.

El problema es que, en ausencia de un evento del navegador, {{Mode}}no se actualiza un enlace de plantilla .

¿Hay alguna manera de activar esta detección de cambio manualmente?

jz87
fuente

Respuestas:

640

Pruebe uno de estos:

  • ApplicationRef.tick()- similar a AngularJS $rootScope.$digest()- es decir, verifique el árbol de componentes completo
  • NgZone.run(callback)- similar a $rootScope.$apply(callback)- es decir, evaluar la función de devolución de llamada dentro de la zona angular. Creo, pero no estoy seguro, que esto termina comprobando el árbol de componentes completo después de ejecutar la función de devolución de llamada.
  • ChangeDetectorRef.detectChanges()- similar a $scope.$digest()- es decir, marque solo este componente y sus elementos secundarios

Puede inyectar ApplicationRef, NgZoneo ChangeDetectorRefen su componente.

Mark Rajcok
fuente
1
Gracias, opté por la tercera solución para no verificar todo, ya que los cambios están bastante localizados. Debería investigar las otras opciones cuando tenga más tiempo. ¿Hay alguna implicación de rendimiento con cada elección?
jz87
36
+1 para ChangeDetectorRef.detectChanges(). los validadores estaban disparando antes de que mi directiva pudiera actualizar el valor de una entrada.
ps2goat
77
ApplicationRef.tick () y ChangeDetectorRef.detectChanges () todavía están presentes en 2.0.0 final.
Max Mumford
51
Solo pensé en mencionar esto. Estos no son métodos estáticos, son métodos de instancia. Necesitará inyectar estas clases como servicios.
Stephen Paul
1
ApplicationRef.tick () ayudó a resolver un problema con FireFox v17 (<20)
Dan J
124

Utilicé la referencia de respuesta aceptada y me gustaría poner un ejemplo, ya que la documentación de Angular 2 es muy difícil de leer, espero que sea más fácil:

  1. Importar NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Agréguelo a su constructor de clase

    constructor(public zone: NgZone, ...args){}
    
  3. Ejecute el código con zone.run:

    this.zone.run(() => this.donations = donations)
    
sitios
fuente
66
¿Dónde deberías poner el zone.runcódigo y qué es exactamente donations?
suku
1
Las donaciones de @suku son cualquier propiedad que desee actualizar, por lo que podría ser this.foo = bar. zone.run va a donde quieras actualizar cosas.
Matthew Opcional Meehan
44
Utilicé esta solución para forzar una actualización de vista al usar document.addEventListener ("resume", callback)
marcovtwout
71

Pude actualizarlo con markForCheck ()

Importar ChangeDetectorRef

import { ChangeDetectorRef } from '@angular/core';

Inyectar e instanciarlo

constructor(private ref: ChangeDetectorRef) { 
}

Finalmente marque la detección de cambio que tendrá lugar

this.ref.markForCheck();

Aquí hay un ejemplo donde markForCheck () funciona y detectChanges () no.

https://plnkr.co/edit/RfJwHqEVJcMU9ku9XNE7?p=preview

EDITAR: Este ejemplo ya no retrata el problema :( Creo que podría estar ejecutando una versión angular más nueva donde se soluciona.

(Presione STOP / RUN para ejecutarlo nuevamente)

Nuno Tomas
fuente
Goo point para detectChanges () no funciona. Noté el mismo problema y descubrí que funciona si la detección de cambios no es OnPush. Sería bueno obtener una explicación para eso ...
Christian
2
Parece que detectChanges realmente está trabajando en este plunker? ¿Me estoy perdiendo de algo?
Jared_C
1
Debe tener en cuenta que ChangeDetectorRef solo funciona en componentes
kevinius
(!) Este es un mal ejemplo, lo siento. El ejemplo no muestra nada. El primer elemento se sobrescribe. Simplemente ajuste los temporizadores un poco ...
Peter Stegnar
Este ejemplo ya no retrata el problema :( Creo que podría estar ejecutando una versión angular más nueva donde se soluciona.
Nuno Tomas
7

En Angular 2+, prueba el decorador @Input

Permite un buen enlace de propiedad entre los componentes primarios y secundarios.

Primero cree una variable global en el elemento primario para contener el objeto / propiedad que se pasará al elemento secundario.

A continuación, cree una variable global en el elemento secundario para contener el objeto / propiedad pasado del elemento primario.

Luego, en el html primario, donde se usa la plantilla secundaria, agregue la notación de corchetes con el nombre de la variable secundaria, luego configúrela igual al nombre de la variable primaria. Ejemplo:

<child-component-template [childVariable] = parentVariable>
</child-component-template>

Finalmente, donde la propiedad secundaria se define en el componente secundario, agregue el decorador de entrada:

@Input()
public childVariable: any

Cuando se actualiza su variable principal, debe pasar las actualizaciones al componente secundario, que actualizará su html.

Además, para activar una función en el componente secundario, eche un vistazo a ngOnChanges.

Jeremy Swagger
fuente
2
NO ... ese es el problema ... si actualiza en el padre ... digamos que por ejemplo se actualiza "por referencia" en un método estático, el niño no lo recogerá ya que no se ha producido la detección de cambios
Bhail
Tengo el mismo problema desde hace días. Intento recuperar datos del backend de PHP y los datos no se actualizan en absoluto. En Microsoft Edge funciona bien, pero en otro navegador no. Sigo recibiendo los datos que obtuve por primera vez, pero si los datos cambian, no se actualizan a la vista
el6976
1

ChangeDetectorRef.detectChanges () - similar a $ scope. $ Digest () - es decir, verifique solo este componente y sus elementos secundarios

Chetann
fuente