Mi componente tiene estilos que dependen de la fecha y hora actual. En mi componente tengo la siguiente función.
private fontColor( dto : Dto ) : string {
// date d'exécution du dto
let dtoDate : Date = new Date( dto.LastExecution );
(...)
let color = "hsl( " + hue + ", 80%, " + (maxLigness - lightnessAmp) + "%)";
return color;
}
lightnessAmp
se calcula a partir de la fecha y hora actual. El color cambia si dtoDate
es en las últimas 24 horas.
El error exacto es el siguiente:
La expresión ha cambiado después de que se verificó. Valor anterior: 'hsl (123, 80%, 49%)'. Valor actual: 'hsl (123, 80%, 48%)'
Sé que la excepción aparece en el modo de desarrollo solo en el momento en que se verifica el valor. Si el valor marcado es diferente del valor actualizado, se genera la excepción.
Así que intenté actualizar la fecha y hora actual en cada ciclo de vida en el siguiente método de enlace para evitar la excepción:
ngAfterViewChecked()
{
console.log( "! changement de la date du composant !" );
this.dateNow = new Date();
}
...pero sin éxito.
angular
typescript
time
styles
components
Anthony Brenelière
fuente
fuente
Respuestas:
Ejecute la detección de cambios explícitamente después del cambio:
fuente
ngOnInit()
generalmente es el primer lugar. Si el código depende de la representación del DOMngAfterViewInit()
ongAfterContentInit()
son las siguientes opciones.ngOnChanges()
es una buena opción si el código debe ejecutarse cada vez que se modifica una entrada.ngDoCheck()
es para la detección de cambios personalizados. En realidad no sé para quéngAfterViewChecked()
se usa mejor. Creo que se llama justo antes o despuésngAfterViewInit()
.clientWidth
, etc.TL; DR
Aunque esta es una solución alternativa, a veces es realmente difícil resolver este problema de una manera más agradable, así que no se culpe si está utilizando este enfoque. Esta bien.
Ejemplos : El problema inicial [ enlace ], resuelto con
setTimeout()
[ enlace ]Como evitar
En general, este error generalmente ocurre después de agregar en algún lugar (incluso en componentes principales / secundarios)
ngAfterViewInit
. Entonces, la primera pregunta es preguntarse: ¿puedo vivir sin élngAfterViewInit
? Quizás mueva el código a alguna parte (ngAfterViewChecked
podría ser una alternativa).Ejemplo : [ enlace ]
también
También las cosas asíncronas
ngAfterViewInit
que afectan al DOM pueden causar esto. También se puede resolver mediantesetTimeout
o agregando eldelay(0)
operador en la tubería:Ejemplo : [ enlace ]
Buena lectura
Buen artículo sobre cómo depurar esto y por qué sucede: enlace
fuente
Como mencionó @leocaseiro en el tema de github .
fuente
Ella te va dos soluciones!
1. Modificar ChangeDetectionStrategy a OnPush
Para esta solución, básicamente le estás diciendo a angular:
La solución rápida:
Modifique su componente para que use
ChangeDetectionStrategy.OnPush
Con esto, las cosas ya no parecen funcionar. Eso es porque a partir de ahora tendrás que hacer que Angular llame
detectChanges()
manualmente.Aquí hay un enlace que me ayudó a entender ChangeDetectionStrategy a la derecha: https://alligator.io/angular/change-detection-strategy/
2. Comprender ExpressionChangedAfterItHasBeenCheckedError
Aquí hay un pequeño extracto de la respuesta de tomonari_t sobre las causas de este error. Intenté incluir solo las partes que me ayudaron a entender esto.
El artículo completo muestra ejemplos de código real sobre cada punto que se muestra aquí.
La causa raíz es el ciclo de vida angular:
Las siguientes operaciones se verifican en el ciclo de resumen:
Y así, el error se produce cuando los valores comparados son diferentes. , el blogger Max Koretskyi declaró:
Y finalmente, aquí hay algunas muestras del mundo real que generalmente causan este error:
Cada muestra se puede encontrar aquí (plunkr), en mi caso el problema era una instanciación dinámica de componentes.
Además, según mi propia experiencia, recomiendo encarecidamente a todos que eviten la
setTimeout
solución, en mi caso causó un bucle "casi" infinito (21 llamadas que no estoy dispuesto a mostrarle cómo provocarlas),Recomendaría tener siempre en cuenta el ciclo de vida angular para que pueda tener en cuenta cómo se verían afectados cada vez que modifique el valor de otro componente. Con este error, Angular te dice:
El mismo blog también dice:
Una breve guía para mí es considerar al menos las siguientes dos cosas al codificar ( intentaré complementarlo con el tiempo ):
@Input
y las@Output
directivas, trate de evitar desencadenar cambios en lyfecycle a menos que el componente esté completamente inicializado.this.cdr.detectChanges();
que pueden provocar más errores, especialmente cuando se trata de una gran cantidad de datos dinámicos.this.cdr.detectChanges();
es obligatorio, asegúrese de que las variables (@Input, @Output, etc
) que se utilizan estén llenas / inicializadas en el gancho de detección correcto (OnInit, OnChanges, AfterView, etc
)también
Si desea comprender completamente Angular Life Hook, le recomiendo que lea la documentación oficial aquí:
fuente
ChangeDetectionStrategy
paraOnPush
arreglarlo por mí. Tengo un componente simple, que tiene[disabled]="isLastPage()"
. Ese método es leer elMatPaginator
-ViewChild y regresarthis.paginator !== undefined ? this.paginator.pageIndex === this.paginator.getNumberOfPages() - 1 : true;
. El paginador no está disponible de inmediato, pero después de que se haya vinculado usando@ViewChild
. Al cambiar, seChangeDetectionStrategy
eliminó el error, y la funcionalidad aún existe como antes. No estoy seguro de qué inconvenientes tengo ahora, ¡pero gracias!OnPush
es que tendrá que usarlothis.cdr.detectChanges()
cada vez que desee que su componente se actualice. Supongo que ya lo estabas usandoEn nuestro caso, FIJAMOS agregando changeDetection en el componente y llama a detectChanges () en ngAfterContentChecked, codifique de la siguiente manera
fuente
Creo que la mejor y más limpia solución que puedas imaginar es esta:
Probado con Angular 5.2.9
fuente
Un pequeño trabajo que usé muchas veces
Principalmente reemplazo "nulo" con alguna variable que uso en el controlador.
fuente
Aunque ya hay muchas respuestas y un enlace a un muy buen artículo sobre detección de cambios, quería dar mis dos centavos aquí. Creo que la verificación está ahí por una razón, así que pensé en la arquitectura de mi aplicación y me di cuenta de que los cambios en la vista pueden abordarse mediante el uso
BehaviourSubject
y el enganche correcto del ciclo de vida. Entonces, esto es lo que hice por una solución.Así que terminé obteniendo la clase de JavaScript subyacente y necesito inicializar mi propio encabezado de calendario para el componente. Eso requiere
ViewChild
que se preste antes de que se preste mi padre, que no es la forma en que funciona Angular. Es por eso que envolví el valor que necesito para mi plantilla enBehaviourSubject<View>(null)
:Luego, cuando puedo estar seguro de que la vista está marcada, actualizo ese tema con el valor de
@ViewChild
:Luego, en mi plantilla, solo uso la
async
tubería. Sin piratería con detección de cambios, sin errores, funciona sin problemas.No dude en preguntar si necesita más detalles.
fuente
Use un valor de formulario predeterminado para evitar el error.
En lugar de usar la respuesta aceptada de aplicar detectChanges () en ngAfterViewInit () (que también resolvió el error en mi caso), decidí guardar un valor predeterminado para un campo de formulario requerido dinámicamente, de modo que cuando el formulario se actualice más tarde, su validez no cambia si el usuario decide cambiar una opción en el formulario que activaría los nuevos campos obligatorios (y provocaría que el botón de envío se deshabilitara).
Esto ahorró un poquito de código en mi componente, y en mi caso se evitó por completo el error.
fuente
this.cdr.detectChanges()
Recibí ese error porque declaró una variable y luego quise
cambiar su valor usando
ngAfterViewInit
para arreglar que cambié de
a
fuente