Pourquoi avons-nous besoin de "ngDoCheck"

je n'arrive pas à comprendre pourquoi j'ai besoin de ngDoCheck crochet de cycle de vie autre que pour la simple notification, en particulier comment l'écriture de code à l'intérieur de celui-ci fait une différence en ce qui concerne la détection de changement. La plupart des exemples que j'ai trouvés montrent inutile d'exemples, comme celui-ci, avec un tas de fonctionnalité de journalisation.

aussi, dans les classes générées Je ne vois pas qu'il soit utilisé pour autre chose que simple notification:

conmponent / wrapper.ngfactory.js

Wrapper_AppComponent.prototype.ngDoCheck = function(view,el,throwOnChange) {
  var self = this;
  var changed = self._changed;
  self._changed = false;
  if (!throwOnChange) {
    if (changed) {
      jit_setBindingDebugInfoForChanges1(view.renderer,el,self._changes);
      self._changes = {};
    }
    self.context.ngDoCheck(); <----------- this calls ngDoCheck on the component
                                           but the result is not used 
                                           anywhere and no params are passed
      }
      return changed;
    };
23
demandé sur Max Wizard K 2017-03-07 11:21:30

3 réponses

Cet article Si vous pensez que ngDoCheck signifie que votre composant est vérifié - lisez cet article explique l'erreur en profondeur.

le contenu de cette réponse est basé sur la version angulaire 2.x.x. Pour la version 4 la plus récente.x.x voir ce post.

il n'y a rien sur internet sur le fonctionnement interne de la détection de changement, donc j'ai dû passer environ une semaine à déboguer les sources, donc cette réponse sera assez technique sur détail.

une application angulaire est un arbre de vues (AppView classe qui est étendue par la classe spécifique au composant générée par le compilateur). Chaque vue a un mode de détection de changement qui vit dans cdMode propriété. La valeur par défaut de cdModeChangeDetectorStatus.CheckAlwayscdMode = 2.

Lorsqu'un cycle de détection de changement s'exécute, chaque vue parent vérifie si elle doit effectuer la détection de changement sur la vue enfant ici:

  detectChanges(throwOnChange: boolean): void {
    const s = _scope_check(this.clazz);
    if (this.cdMode === ChangeDetectorStatus.Checked ||
        this.cdMode === ChangeDetectorStatus.Errored)
      return;
    if (this.cdMode === ChangeDetectorStatus.Destroyed) {
      this.throwDestroyedError('detectChanges');
    }
    this.detectChangesInternal(throwOnChange); <---- performs CD on child view

this points child afficher. Donc, si cdModeChangeDetectorStatus.Checked=1, la détection de changement est sautée pour l'enfant immédiat et tous ses descendants à cause de cette ligne.

if (this.cdMode === ChangeDetectorStatus.Checked ||
        this.cdMode === ChangeDetectorStatus.Errored)
      return;

changeDetection: ChangeDetectionStrategy.OnPush n'est tout simplement fixe cdModeChangeDetectorStatus.CheckOnce = 0, donc après la première détection de changement la vue de l'enfant aura son cdModeChangeDetectorStatus.Checked = 1 à cause de ce code:

if (this.cdMode === ChangeDetectorStatus.CheckOnce) 
     this.cdMode = ChangeDetectorStatus.Checked;

ce Qui signifie que la prochaine fois qu'un cycle de détection de changement commencera, il n'y aura pas de détection de changement effectuée pour la vue de l'enfant.

il y a peu d'options pour lancer la détection de changement pour une telle vue. La première est de modifier la vue enfant cdModeChangeDetectorStatus.CheckOnce, ce qui peut être fait en utilisant this._changeRef.markForCheck()ngDoCheck cycle de vie du crochet:

  constructor(private _changeRef: ChangeDetectorRef) {   }

  ngDoCheck() {
    this._changeRef.markForCheck();
  }

tout simplement cdMode de la vue actuelle et de ses parents à ChangeDetectorStatus.CheckOnce, donc la prochaine fois que la détection de changement est effectuée la vue courante est vérifier.

Vérifier un exemple complet ici dans les sources, mais voici l'essentiel:

      constructor(ref: ChangeDetectorRef) {
        setInterval(() => {
          this.numberOfTicks ++
          // the following is required, otherwise the view will not be updated
          this.ref.markForCheck();
          ^^^^^^^^^^^^^^^^^^^^^^^^
        }, 1000);
      }

la deuxième option est call detectChanges sur la vue elle-même qui va exécuter la détection du changement sur la vue actuelle si cdMode n'est pas ChangeDetectorStatus.Checked ou ChangeDetectorStatus.Errored. Depuis avec onPush angulaire fixe cdModeChangeDetectorStatus.CheckOnce angulaires qui va exécuter la détection de changement.

ngDoCheck ne remplace pas la détection modifiée, elle s'appelle simplement sur chaque cycle de détection modifié et son seul travail est de définir la vue actuelle cdModecheckOnce, de sorte que lors du prochain cycle de détection de changement il est vérifié pour les changements. Voir cette réponse pour plus de détails. Si le mode de détection de changement de la vue courante est checkAlways (défini par défaut si la stratégie onPush n'est pas utilisée),ngDocCheck semblent être d'aucune utilité.

44
répondu Max Wizard K 2017-09-09 10:48:03

DoCheck l'interface est utilisée pour détecter manuellement les changements que la détection de changement angulaire a négligés. Une utilisation pourrait être quand vous changez le ChangeDetectionStrategy de votre composant, mais vous savez qu'une propriété d'un objet va changer.

il est plus efficace de vérifier ce changement que de laisser le changeDetector tourner à travers tout votre composant

let obj = {
  iChange: 'hiii'
}

Si vous utilisez obj.iChange à l'intérieur de votre modèle, angular ne le détectera pas si ceci la valeur change, parce que la référence de obj lui-même ne change pas. Vous avez besoin de mettre en œuvre un ngDoCheck à vérifier si la valeur a changé, et demander un detectChanges sur le module changeDetector de votre composant.

de la documentation angulaire sur DoCheck

ngDoCheck crochet peut détecter lorsque le nom du héros a changé, il a un coût effrayant. Ce crochet est appelé avec une fréquence énorme - après chaque cycle de détection de changement peu importe d'où le changement est survenu. Il est appelé plus de vingt fois dans cet exemple avant que l'utilisateur puisse faire quoi que ce soit.

la plupart de ces vérifications initiales sont déclenchées par le premier rendu par Angular de données non reliées ailleurs sur la page. Une simple fusion dans une autre boîte déclenche un appel. Relativement peu d'appels révèlent des changements réels aux données pertinentes. Il est clair que notre mise en œuvre doit être très légère ou l'expérience de l'utilisateur en souffrira.

testé exemple

@Component({
   selector: 'test-do-check',
   template: `
      <div [innerHtml]="obj.changer"></div>
   `, 
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestDoCheckComponent implements DoCheck, OnInit {

    public obj: any = {
       changer: 1
    };

    private _oldValue: number = 1;

    constructor(private _changeRef: ChangeDetectorRef){}

    ngOnInit() {
       setInterval(() => {
           this.obj.changer += 1;
       }, 1000);
    }

    ngDoCheck() {
       if(this._oldValue !== this.obj.changer) {
           this._oldValue = this.obj.changer;

           //disable this line to see the counter not moving
           this._changeRef.detectChanges();
       }
    }

}
7
répondu PierreDuc 2017-03-07 09:20:21

// ce qui suit est nécessaire, sinon la vue ne sera pas mis à jour

ceci.réf.markForCheck(); ^^^^^^^^^^^^^^^^^^^^^^^^

Salut, Maxim @AngularInDepth.com La vue est mise à jour sans appel de ceci.réf.markForCheck (). J'ai fait des tests à Constance et ngOnInit. Cochez cette

0
répondu Yerkon 2018-03-03 05:12:33