Déclenchement manuel de la détection des modifications dans Angular


387

J'écris un composant angulaire qui a une propriété Mode(): string.

Je voudrais pouvoir définir cette propriété par programme, pas en réponse à un événement.

Le problème est qu'en l'absence d'un événement de navigateur, une liaison de modèle {{Mode}}n'est pas mise à jour.

Existe-t-il un moyen de déclencher cette détection de changement manuellement?

Réponses:


640

Essayez l'une de ces options:

  • ApplicationRef.tick()- similaire à AngularJS $rootScope.$digest()- c.-à-d., vérifiez l'arborescence complète des composants
  • NgZone.run(callback)- similaire à $rootScope.$apply(callback)- c.- à -d. évaluer la fonction de rappel à l'intérieur de la zone angulaire. Je pense, mais je ne suis pas sûr, que cela finit par vérifier l'arborescence complète des composants après l'exécution de la fonction de rappel.
  • ChangeDetectorRef.detectChanges()- similaire à $scope.$digest()- c.- à -d., cochez uniquement ce composant et ses enfants

Vous pouvez injecter ApplicationRef, NgZoneou ChangeDetectorRefdans votre composant.


1
Merci, j'ai opté pour la 3ème solution pour ne pas tout vérifier, car les changements sont assez localisés. Je devrais étudier les autres options lorsque j'aurai plus de temps. Y a-t-il des implications de performance avec chaque choix?
jz87

36
+1 pour ChangeDetectorRef.detectChanges(). les validateurs se déclenchaient avant que ma directive puisse mettre à jour la valeur d'une entrée.
ps2goat

7
ApplicationRef.tick () et ChangeDetectorRef.detectChanges () sont toujours présents dans la version 2.0.0 finale.
Max Mumford

51
Je pensais juste le mentionner. Ce ne sont pas des méthodes statiques, ce sont des méthodes d'instance. Vous devrez injecter ces classes en tant que services.
Stephen Paul

1
ApplicationRef.tick () a aidé à résoudre un problème avec FireFox v17 (<20)
Dan J

124

J'ai utilisé une référence de réponse acceptée et je voudrais mettre un exemple, car la documentation Angular 2 est très très difficile à lire, j'espère que c'est plus facile:

  1. Importer NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Ajoutez-le à votre constructeur de classe

    constructor(public zone: NgZone, ...args){}
    
  3. Exécutez le code avec zone.run:

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

6
où devez-vous mettre le zone.runcode et quel est-il exactement donations?
suku

1
@suku donations est une propriété que vous souhaitez mettre à jour, il peut donc s'agir de this.foo = bar. zone.run va où vous voulez mettre à jour des trucs.
Matthew Facultatif Meehan

4
J'ai utilisé cette solution pour forcer une mise à jour de la vue lors de l'utilisation de document.addEventListener ("reprendre", rappel)
marcovtwout

71

J'ai pu le mettre à jour avec markForCheck ()

Importer ChangeDetectorRef

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

Injecter et instancier

constructor(private ref: ChangeDetectorRef) { 
}

Enfin, marquez la détection des changements

this.ref.markForCheck();

Voici un exemple où markForCheck () fonctionne et detectChanges () ne fonctionne pas.

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

EDIT: Cet exemple ne décrit plus le problème :( Je pense qu'il pourrait exécuter une version angulaire plus récente où il est résolu.

(Appuyez sur STOP / RUN pour l'exécuter à nouveau)


Goo point pour detectChanges () ne fonctionne pas. J'avais remarqué le même problème et constaté que cela fonctionne si la détection de changement n'est pas OnPush. Ce serait bien d'avoir une explication à cela ...
Christian

2
Il semble que detectChanges fonctionne réellement dans ce plongeur? Suis-je en train de manquer quelque chose?
Jared_C

1
Vous devez noter que ChangeDetectorRef ne fonctionne que dans les composants
kevinius

(!) C'est un mauvais exemple, je suis désolé. L'exemple ne montre rien. Le premier élément est simplement écrasé. Ajustez un peu les minuteries ...
Peter Stegnar

Cet exemple ne décrit plus le problème :( Je pense qu'il pourrait exécuter une nouvelle version angulaire où il est résolu.
Nuno Tomas

7

Dans Angular 2+, essayez le décorateur @Input

Il permet une belle liaison de propriété entre les composants parent et enfant.

Créez d'abord une variable globale dans le parent pour contenir l'objet / la propriété qui sera transmis à l'enfant.

Créez ensuite une variable globale dans l'enfant pour contenir l'objet / la propriété transmis par le parent.

Ensuite, dans le html parent, où le modèle enfant est utilisé, ajoutez une notation entre crochets avec le nom de la variable enfant, puis définissez-la égale au nom de la variable parent. Exemple:

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

Enfin, lorsque la propriété enfant est définie dans le composant enfant, ajoutez le décorateur d'entrée:

@Input()
public childVariable: any

Lorsque votre variable parent est mise à jour, elle doit transmettre les mises à jour au composant enfant, qui mettra à jour son code HTML.

De plus, pour déclencher une fonction dans le composant enfant, jetez un œil à ngOnChanges.


2
NON ... c'est le problème ... si vous mettez à jour dans le parent ... disons que pour exmaple est mis à jour "par référence" dans une méthode statique, l'enfant ne le ramassera pas car la détection de changement
n'a pas

J'ai le même problème depuis des jours maintenant. J'essaie de récupérer des données du backend PHP et les données ne sont pas mises à jour du tout. Sur Microsoft Edge, cela fonctionne bien, mais pas sur un autre navigateur. Je continue de recevoir les données que j'ai eues pour la première fois, mais si les données changent, elles ne sont pas mises à jour à l'écran
el6976

1

ChangeDetectorRef.detectChanges () - similaire à $ scope. $ Digest () - c'est-à-dire, vérifiez uniquement ce composant et ses enfants

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.