Attivazione manuale del rilevamento delle modifiche in Angolare


387

Sto scrivendo un componente angolare che ha una proprietà Mode(): string.

Vorrei poter impostare questa proprietà a livello di codice non in risposta a nessun evento.

Il problema è che in assenza di un evento del browser, l'associazione di un modello {{Mode}}non si aggiorna.

C'è un modo per attivare manualmente questo rilevamento delle modifiche?

Risposte:


640

Prova uno di questi:

  • ApplicationRef.tick()- simile a quello di AngularJS $rootScope.$digest()- ovvero, controlla l'albero dei componenti completo
  • NgZone.run(callback)- simile a $rootScope.$apply(callback)- ovvero, valuta la funzione di richiamata all'interno della zona angolare. Penso, ma non sono sicuro, che questo finisca per controllare l'albero dei componenti completo dopo aver eseguito la funzione di callback.
  • ChangeDetectorRef.detectChanges()- simile a $scope.$digest()- cioè, controlla solo questo componente e i suoi figli

Puoi iniettare ApplicationRef, NgZoneo ChangeDetectorRefnel tuo componente.


1
Grazie, ho optato per la terza soluzione in modo da non controllare tutto, poiché le modifiche sono abbastanza localizzate. Dovrei studiare le altre opzioni quando ho più tempo. Ci sono implicazioni sulle prestazioni con ciascuna scelta?
jz87

36
+1 per ChangeDetectorRef.detectChanges(). i validatori venivano attivati ​​prima che la mia direttiva potesse aggiornare il valore di un input.
ps2goat,

7
ApplicationRef.tick () e ChangeDetectorRef.detectChanges () sono ancora presenti in 2.0.0 final.
Max Mumford,

51
Ho pensato di menzionarlo. Questi non sono metodi statici, sono metodi di istanza. Dovrai iniettare queste classi come servizi.
Stephen Paul,

1
ApplicationRef.tick () ha aiutato a risolvere un problema con FireFox v17 (<20)
Dan J

124

Ho usato il riferimento alla risposta accettata e vorrei fare un esempio, poiché la documentazione di Angular 2 è molto difficile da leggere, spero che sia più semplice:

  1. Importazione NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Aggiungilo al costruttore della tua classe

    constructor(public zone: NgZone, ...args){}
    
  3. Esegui il codice con zone.run:

    this.zone.run(() => this.donations = donations)
    

6
dove dovresti inserire il zone.runcodice e cos'è esattamente donations?
suku

1
@suku donations è qualsiasi proprietà che desideri aggiornare, quindi potrebbe essere this.foo = bar. zone.run va dove vuoi aggiornare roba.
Matthew Opzionale Meehan,

4
Ho usato questa soluzione per forzare un aggiornamento della vista durante l'utilizzo di document.addEventListener ("resume", callback)
marcovtwout

71

Sono stato in grado di aggiornarlo con markForCheck ()

Importa ChangeDetectorRef

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

Iniettare e istanziarlo

constructor(private ref: ChangeDetectorRef) { 
}

Infine segna il rilevamento delle modifiche da effettuare

this.ref.markForCheck();

Ecco un esempio in cui markForCheck () funziona e detectChanges () no.

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

EDIT: Questo esempio non descrive più il problema :( credo che potrebbe essere in esecuzione una versione angolare più recente in cui è stato risolto.

(Premere STOP / RUN per eseguirlo di nuovo)


Punto di goo per detectChanges () non funzionante. Avevo notato lo stesso problema e ho scoperto che funziona se il rilevamento delle modifiche non è OnPush. Sarebbe bello avere una spiegazione per questo ...
Christian

2
Sembra che detectChanges stia effettivamente lavorando in questo plunker? Mi sto perdendo qualcosa?
Jared_C,

1
Si noti che ChangeDetectorRef funziona solo in Componenti
kevinius

(!) Questo è un cattivo esempio, mi dispiace. L'esempio non mostra nulla. Il primo elemento viene sovrascritto. Regola un po 'i timer ...
Peter Stegnar il

Questo esempio non descrive più il problema :( credo che potrebbe essere in esecuzione una versione angolare più recente in cui è stato risolto.
Nuno Tomas,

7

In Angular 2+, prova il decoratore @Input

Permette un bel legame di proprietà tra i componenti padre e figlio.

Innanzitutto creare una variabile globale nel genitore per contenere l'oggetto / proprietà che verrà passata al figlio.

Quindi creare una variabile globale nel figlio per contenere l'oggetto / proprietà passati dal genitore.

Quindi nel codice HTML principale, in cui viene utilizzato il modello figlio, aggiungi la notazione tra parentesi quadre con il nome della variabile figlio, quindi impostala uguale al nome della variabile padre. Esempio:

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

Infine, dove la proprietà figlio è definita nel componente figlio, aggiungi il decoratore di input:

@Input()
public childVariable: any

Quando la variabile principale viene aggiornata, dovrebbe passare gli aggiornamenti al componente figlio, che aggiornerà il suo codice HTML.

Inoltre, per attivare una funzione nel componente figlio, dai un'occhiata a ngOnChanges.


2
NO ... questo è il problema ... se si aggiorna nel genitore ... diciamo che per exmaple viene aggiornato "per riferimento" in un metodo statico il bambino non lo raccoglierà poiché il rilevamento delle modifiche non si è verificato
Bhail

Ho lo stesso problema da giorni ormai. Provo a recuperare i dati dal back-end di PHP e i dati non si aggiornano affatto. Su Microsoft Edge funziona bene, ma su altri browser non funziona. Continuo a ottenere i dati che ho iniziato per la prima volta, ma se i dati cambiano non vengono aggiornati alla vista
el6976

1

ChangeDetectorRef.detectChanges () - simile a $ scope. $ Digest () - cioè controlla solo questo componente e i suoi figli

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.