Mon composant a des styles qui dépendent de la date / heure actuelle. Dans mon composant, j'ai la fonction suivante.
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
est calculé à partir de la date / heure actuelle. La couleur change si dtoDate
c'est dans les dernières 24 heures.
L'erreur exacte est la suivante:
L'expression a changé après avoir été vérifiée. Valeur précédente: 'hsl (123, 80%, 49%)'. Valeur actuelle: 'hsl (123, 80%, 48%)'
Je sais que l'exception n'apparaît en mode développement qu'au moment où la valeur est vérifiée. Si la valeur vérifiée est différente de la valeur mise à jour, l'exception est levée.
J'ai donc essayé de mettre à jour la date et l'heure actuelle à chaque cycle de vie dans la méthode de crochet suivante pour éviter l'exception:
ngAfterViewChecked()
{
console.log( "! changement de la date du composant !" );
this.dateNow = new Date();
}
... mais sans succès.
angular
typescript
time
styles
components
Anthony Brenelière
la source
la source
Réponses:
Exécutez la détection des modifications explicitement après la modification:
la source
ngOnInit()
c'est généralement le premier endroit. Si le code dépend du DOM en cours de rendungAfterViewInit()
oungAfterContentInit()
des options suivantes.ngOnChanges()
est un bon ajustement si le code doit être exécuté à chaque fois qu'une entrée a été modifiée.ngDoCheck()
est pour la détection de changement personnalisé. En fait, je ne sais pas ce quingAfterViewChecked()
est le mieux utilisé. Je pense que ça s'appelle juste avant ou aprèsngAfterViewInit()
.clientWidth
, etc.TL; DR
Bien que ce soit une solution de contournement, il est parfois très difficile de résoudre ce problème de manière plus agréable, alors ne vous blâmez pas si vous utilisez cette approche. C'est bon.
Exemples : Le problème initial [ lien ], résolu avec
setTimeout()
[ lien ]Comment éviter
En général, cette erreur se produit généralement après avoir ajouté quelque part (même dans les composants parents / enfants)
ngAfterViewInit
. La première question est donc de vous poser la question: puis-je vivre sansngAfterViewInit
? Peut-être que vous déplacez le code quelque part (ngAfterViewChecked
peut être une alternative).Exemple : [ lien ]
Aussi
Des éléments asynchrones
ngAfterViewInit
qui affectent le DOM peuvent également en être la cause. Peut également être résolu viasetTimeout
ou en ajoutant l'delay(0)
opérateur dans le tube:Exemple : [ lien ]
Bonne lecture
Bon article sur la façon de déboguer et pourquoi cela se produit: lien
la source
Comme mentionné par @leocaseiro sur le problème de github .
la source
Son vous allez deux solutions!
1. Modifiez ChangeDetectionStrategy en OnPush
Pour cette solution, vous dites essentiellement angulaire:
La solution rapide:
Modifiez votre composant pour qu'il utilise
ChangeDetectionStrategy.OnPush
Avec cela, les choses ne semblent plus fonctionner. En effet, à partir de maintenant, vous devrez effectuer un appel Angular
detectChanges()
manuellement.Voici un lien qui m'a aidé à comprendre ChangeDetectionStrategy à droite: https://alligator.io/angular/change-detection-strategy/
2. Comprendre ExpressionChangedAfterItHasBeenCheckedError
Voici un petit extrait de la réponse de tomonari_t sur les causes de cette erreur, j'ai essayé de n'inclure que les parties qui m'ont aidé à comprendre cela.
L'article complet montre de vrais exemples de code sur chaque point montré ici.
La cause première est le cycle de vie angulaire:
Les opérations suivantes sont en cours de vérification lors du cycle de digestion:
Et ainsi, l'erreur est générée lorsque les valeurs comparées sont différentes. , le blogueur Max Koretskyi a déclaré:
Et enfin, voici quelques exemples du monde réel qui provoquent généralement cette erreur:
Chaque échantillon peut être trouvé ici (plunkr), dans mon cas, le problème était une instanciation de composant dynamique.
De plus, par ma propre expérience, je recommande fortement à tout le monde d'éviter la
setTimeout
solution, dans mon cas a provoqué une boucle "presque" infinie (21 appels dont je ne veux pas vous montrer comment les provoquer),Je recommanderais de toujours garder à l'esprit le cycle de vie angulaire afin que vous puissiez prendre en compte la façon dont ils seraient affectés chaque fois que vous modifiez la valeur d'un autre composant. Avec cette erreur Angular vous dit:
Le même blog dit également:
Un petit guide pour moi est de considérer au moins les deux choses suivantes lors du codage ( je vais essayer de le compléter au fil du temps ):
@Input
et,@Output
essayez d'éviter de déclencher des modifications de lyfecycle à moins que le composant ne soit complètement initialisé.this.cdr.detectChanges();
car ils peuvent déclencher plus d'erreurs, en particulier lorsque vous traitez avec beaucoup de données dynamiquesthis.cdr.detectChanges();
est obligatoire, assurez-vous que les variables (@Input, @Output, etc
) utilisées sont remplies / initialisées au crochet de détection droit (OnInit, OnChanges, AfterView, etc
)Aussi
Si vous voulez bien comprendre Angular Life Hook, je vous recommande de lire la documentation officielle ici:
la source
ChangeDetectionStrategy
pour leOnPush
réparer pour moi. J'ai un composant simple, qui a[disabled]="isLastPage()"
. Cette méthode lit leMatPaginator
-ViewChild et retournethis.paginator !== undefined ? this.paginator.pageIndex === this.paginator.getNumberOfPages() - 1 : true;
. Le paginateur n'est pas disponible tout de suite, mais après avoir été lié à l'aide de@ViewChild
. Changer l'ChangeDetectionStrategy
erreur a supprimé l'erreur - et la fonctionnalité existe toujours comme avant. Je ne sais pas quels inconvénients j'ai maintenant, mais merci!OnPush
est que vous devrez utiliserthis.cdr.detectChanges()
chaque fois que vous souhaitez que votre composant soit actualisé. Je suppose que vous l'utilisiez déjàDans notre cas, nous FIXE en ajoutant changeDetection dans le composant et appelons detectChanges () dans ngAfterContentChecked, code comme suit
la source
Je pense que la solution la meilleure et la plus propre que vous puissiez imaginer est la suivante:
Testé avec Angular 5.2.9
la source
Un petit travail autour que j'ai utilisé plusieurs fois
Je remplace principalement "null" par une variable que j'utilise dans le contrôleur.
la source
Bien qu'il y ait déjà beaucoup de réponses et un lien vers un très bon article sur la détection des changements, je voulais donner mes deux cents ici. Je pense que la vérification est là pour une raison, j'ai donc pensé à l'architecture de mon application et réalisé que les changements dans la vue peuvent être traités en utilisant
BehaviourSubject
et le crochet de cycle de vie correct. Alors, voici ce que j'ai fait pour trouver une solution.J'ai donc fini par obtenir la classe JavaScript sous-jacente et j'ai besoin d'initialiser mon propre en-tête de calendrier pour le composant. Cela nécessite le
ViewChild
rendu avant que mon parent ne soit rendu, ce qui n'est pas la façon dont Angular fonctionne. C'est pourquoi j'ai inclus la valeur dont j'ai besoin pour mon modèle dans unBehaviourSubject<View>(null)
:Ensuite, lorsque je peux être sûr que la vue est vérifiée, je mets à jour ce sujet avec la valeur de
@ViewChild
:Ensuite, dans mon modèle, j'utilise simplement le
async
tuyau. Pas de piratage avec détection des changements, pas d'erreurs, fonctionne sans problème.N'hésitez pas à demander si vous avez besoin de plus de détails.
la source
Utilisez une valeur de formulaire par défaut pour éviter l'erreur.
Au lieu d'utiliser la réponse acceptée consistant à appliquer detectChanges () dans ngAfterViewInit () (qui a également résolu l'erreur dans mon cas), j'ai plutôt décidé d'enregistrer une valeur par défaut pour un champ de formulaire dynamiquement requis, de sorte que lorsque le formulaire est mis à jour ultérieurement, sa validité n'est pas modifiée si l'utilisateur décide de modifier une option sur le formulaire qui déclencherait les nouveaux champs obligatoires (et entraînerait la désactivation du bouton d'envoi).
Cela a sauvé un tout petit peu de code dans mon composant et, dans mon cas, l'erreur a été complètement évitée.
la source
this.cdr.detectChanges()
J'ai eu cette erreur parce que j'ai déclaré une variable et que je voulais plus tard
changer sa valeur en utilisant
ngAfterViewInit
pour réparer que je suis passé de
à
la source