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;
};
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 cdMode
ChangeDetectorStatus.CheckAlways
cdMode = 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
où this
points child
afficher. Donc, si cdMode
ChangeDetectorStatus.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 cdMode
ChangeDetectorStatus.CheckOnce = 0
, donc après la première détection de changement la vue de l'enfant aura son cdMode
ChangeDetectorStatus.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 cdMode
ChangeDetectorStatus.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 cdMode
ChangeDetectorStatus.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 cdMode
checkOnce
, 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é.
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();
}
}
}
// 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