vistas spa pagina inicio formularios español datos angular angular2-docheck

angular - spa - ¿Por qué necesitamos `ngDoCheck`



formularios en angular 5 (3)

// se requiere lo siguiente, de lo contrario la vista no se actualizará

this.ref.markForCheck (); ^^^^^^^^^^^^^^^^^^^^^^^^

Hola, Maxim @ AngularInDepth.com La vista se actualiza sin llamar a this.ref.markForCheck () . He probado en consturctor y ngOnInit. Mira esto

Parece que no puedo entender por qué necesito el gancho del ciclo de vida de ngDoCheck que no sea una simple notificación, en particular, la forma en que escribir un código en el interior hace una diferencia en lo que respecta a la detección de cambios. La mayoría de los ejemplos que he encontrado muestran ejemplos inútiles, como este , con un montón de funciones de registro.

Además, en las clases generadas no veo que se use para otra cosa que no sea una simple notificación:

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; };


Este excelente artículo Si cree que ngDoCheck significa que su componente está siendo revisado, lea este artículo que explica el error en profundidad.

El contenido de esta respuesta se basa en la versión angular 2.xx. Para la versión más reciente 4.xx vea esta publicación .

No hay nada en Internet sobre el funcionamiento interno de la detección de cambios, por lo que tuve que dedicar aproximadamente una semana a la depuración de fuentes, por lo que esta respuesta será bastante técnica en los detalles.

Una aplicación angular es un árbol de views (clase AppView que se extiende por la clase específica del componente generada por el compilador). Cada vista tiene un modo de detección de cambios que vive en la propiedad cdMode . El valor predeterminado para cdMode es ChangeDetectorStatus.CheckAlways , que es cdMode = 2 .

Cuando se ejecuta un ciclo de detección de cambios, cada vista principal comprueba si debe realizar la detección de cambios en la vista secundaria here :

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

donde this apunta a la vista child . Entonces, si cdMode es ChangeDetectorStatus.Checked=1 , la detección de cambio se omite para el hijo inmediato y todos sus descendientes debido a esta línea.

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

Lo que hace changeDetection: ChangeDetectionStrategy.OnPush es simplemente establece cdMode en ChangeDetectorStatus.CheckOnce = 0 , por lo que después de la primera ejecución de detección de cambios, la vista secundaria tendrá su cdMode establecido en ChangeDetectorStatus.Checked = 1 debido a este código :

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

Lo que significa que la próxima vez que comience un ciclo de detección de cambios no se realizará ninguna detección de cambios para la vista secundaria.

Hay pocas opciones de cómo ejecutar la detección de cambios para dicha vista. Lo primero es cambiar el cdMode la vista cdMode a ChangeDetectorStatus.CheckOnce , lo que se puede hacer usando this._changeRef.markForCheck() en el gancho del ciclo de vida de ngDoCheck :

constructor(private _changeRef: ChangeDetectorRef) { } ngDoCheck() { this._changeRef.markForCheck(); }

Esto simplemente cambia cdMode de la vista actual y sus padres a ChangeDetectorStatus.CheckOnce , por lo que la próxima vez que se realice la detección de cambios, se verifica la vista actual.

Verifique un ejemplo completo aquí en las fuentes , pero aquí está la esencia de esto:

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

La segunda opción es llamar a detectChanges en la vista misma, que here en la vista actual si cdMode no es ChangeDetectorStatus.Checked o ChangeDetectorStatus.Errored . Dado que con onPush angular establece cdMode en ChangeDetectorStatus.CheckOnce , angular ejecutará la detección de cambios.

Por ngDoCheck tanto, ngDoCheck no anula el cambio de detección, simplemente se ngDoCheck en cada ciclo de detección cambiado y el único trabajo es configurar el modo de visualización de cdMode actual como checkOnce , de modo que durante el próximo ciclo de detección de cambios se verifique los cambios. Vea esta respuesta para más detalles. Si el modo de detección de cambio de la vista actual es checkAlways (establecido de forma predeterminada si no se usa la estrategia onPush), ngDocCheck parece no ser de utilidad.


La interfaz DoCheck se utiliza para detectar cambios manualmente que la detección de cambios angulares ha pasado por alto. Un uso podría ser cuando cambia la ChangeDetectionStrategy de cambio de ChangeDetectionStrategy de su componente, pero sabe que una propiedad de un objeto cambiará.

Es más eficiente verificar este cambio, que dejar que el detector de cambios funcione a través de todo su componente

let obj = { iChange: ''hiii'' }

Si usa obj.iChange dentro de su plantilla, angular no lo detectará si este valor cambia, porque la referencia de obj sí no cambia. ngDoCheck implementar un ngDoCheck para verificar si el valor ha cambiado y llamar a detectChanges en el detectChanges de su componente.

De la documentación angular sobre DoCheck

Mientras que el gancho ngDoCheck puede detectar cuando el nombre del héroe ha cambiado, tiene un costo espantoso. Este gancho se llama con una frecuencia enorme, después de cada ciclo de detección de cambios, sin importar dónde ocurrió el cambio. Se llama más de veinte veces en este ejemplo antes de que el usuario pueda hacer algo.

La mayoría de estas comprobaciones iniciales son activadas por la primera representación de Angular de datos no relacionados en otra parte de la página. El mero hacer clic en otro cuadro de entrada activa una llamada. Relativamente pocas llamadas revelan cambios reales a los datos pertinentes. Claramente, nuestra implementación debe ser muy liviana o la experiencia del usuario se verá afectada.

ejemplo probado

@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(); } } }