Meu componente possui estilos que dependem da data e hora atuais. No meu componente, tenho a seguinte função.
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
é calculado a partir da data e hora atuais. A cor muda se dtoDate
estiver nas últimas 24 horas.
O erro exato é o seguinte:
A expressão foi alterada após a verificação. Valor anterior: 'hsl (123, 80%, 49%)'. Valor atual: 'hsl (123, 80%, 48%)'
Eu sei que a exceção aparece no modo de desenvolvimento apenas no momento em que o valor é verificado. Se o valor verificado for diferente do valor atualizado, a exceção será lançada.
Por isso, tentei atualizar a data e hora atual em cada ciclo de vida no seguinte método de gancho para evitar a exceção:
ngAfterViewChecked()
{
console.log( "! changement de la date du composant !" );
this.dateNow = new Date();
}
... mas sem sucesso.
angular
typescript
time
styles
components
Anthony Brenelière
fonte
fonte
Respostas:
Execute a detecção de alterações explicitamente após a alteração:
fonte
ngOnInit()
geralmente é o primeiro lugar. Se o código depende do DOM que está sendo renderizadongAfterViewInit()
oungAfterContentInit()
são as próximas opções.ngOnChanges()
é um bom ajuste se o código for executado toda vez que uma entrada for alterada.ngDoCheck()
é para detecção personalizada de alterações. Na verdade, não sei para quengAfterViewChecked()
serve melhor. Eu acho que é chamado antes ou depoisngAfterViewInit()
.clientWidth
etc.TL; DR
Embora essa seja uma solução alternativa, às vezes é realmente difícil resolver esse problema da melhor maneira possível; portanto, não se culpe se estiver usando essa abordagem. Tudo bem.
Exemplos : o problema inicial [ link ], resolvido com
setTimeout()
[ link ]Como evitar
Em geral, esse erro geralmente ocorre após a adição de algum lugar (mesmo nos componentes pai / filho)
ngAfterViewInit
. Então, a primeira pergunta é se perguntar - posso viver semngAfterViewInit
? Talvez você mova o código para algum lugar (ngAfterViewChecked
pode ser uma alternativa).Exemplo : [ link ]
Além disso
Também coisas assíncronas
ngAfterViewInit
que afetam o DOM podem causar isso. Também pode ser resolvido viasetTimeout
ou adicionando odelay(0)
operador no tubo:Exemplo : [ link ]
Nice Reading
Bom artigo sobre como depurar isso e por que isso acontece: link
fonte
Como mencionado por @leocaseiro na questão do github .
fonte
Ela você vai duas soluções!
1. Modifique ChangeDetectionStrategy para OnPush
Para esta solução, você está basicamente dizendo angular:
A solução rápida:
Modifique seu componente para que ele use
ChangeDetectionStrategy.OnPush
Com isso, as coisas parecem não funcionar mais. Isso porque a partir de agora você terá que fazer a chamada Angular
detectChanges()
manualmente.Aqui está um link que me ajudou a entender o ChangeDetectionStrategy corretamente: https://alligator.io/angular/change-detection-strategy/
2. Entendendo ExpressionChangedAfterItHasBeenCheckedError
Aqui está um pequeno extrato da resposta tomonari_t sobre as causas desse erro. Tentei incluir apenas as partes que me ajudaram a entender isso.
O artigo completo mostra exemplos de códigos reais sobre todos os pontos mostrados aqui.
A causa raiz é o ciclo de vida angular:
As seguintes operações estão sendo verificadas nos ciclos de resumo:
E assim, o erro é gerado quando os valores comparados são diferentes. , o blogueiro Max Koretskyi afirmou:
E, finalmente, aqui estão algumas amostras do mundo real que geralmente causam esse erro:
Cada amostra pode ser encontrada aqui (plunkr); no meu caso, o problema era uma instanciação de componente dinâmico.
Além disso, pela minha própria experiência, recomendo fortemente que todos evitem a
setTimeout
solução, no meu caso causou um loop infinito "quase" (21 chamadas que não estou disposto a mostrar como provocá-las),Eu recomendaria ter sempre em mente os ciclos de vida angulares para que você possa levar em consideração como eles seriam afetados toda vez que você modificar o valor de outro componente. Com este erro, a Angular está lhe dizendo:
O mesmo blog também diz:
Um pequeno guia para mim é considerar pelo menos as duas coisas a seguir durante a codificação ( tentarei complementá-lo com o tempo ):
@Input
e@Output
directivas tentar evitar desencadear mudanças lyfecycle a menos que o componente é completamente inicializado.this.cdr.detectChanges();
pois elas podem acionar mais erros, especialmente quando você está lidando com muitos dados dinâmicosthis.cdr.detectChanges();
for obrigatório, verifique se as variáveis (@Input, @Output, etc
) usadas estão preenchidas / inicializadas no gancho de detecção direito (OnInit, OnChanges, AfterView, etc
)Além disso
Se você deseja entender completamente o Angular Life Hook, recomendo que você leia a documentação oficial aqui:
fonte
ChangeDetectionStrategy
paraOnPush
corrigi-lo para mim. Eu tenho um componente simples, que tem[disabled]="isLastPage()"
. Esse método está lendo oMatPaginator
-ViewChild e retornandothis.paginator !== undefined ? this.paginator.pageIndex === this.paginator.getNumberOfPages() - 1 : true;
. O paginador não está disponível imediatamente, mas depois de ter sido vinculado ao uso@ViewChild
. Alterar oChangeDetectionStrategy
erro removido - e a funcionalidade ainda existe como antes. Não tenho certeza de quais inconvenientes tenho agora, mas obrigado!OnPush
é que você precisará usarthis.cdr.detectChanges()
toda vez que quiser que seu componente seja atualizado. Eu acho que você já estava usandoNo nosso caso, corrigimos adicionando changeDetection no componente e chamamos detectChanges () em ngAfterContentChecked, codifique da seguinte maneira
fonte
Eu acho que a melhor e mais limpa solução que você pode imaginar é esta:
Testado com Angular 5.2.9
fonte
Um pequeno trabalho que usei muitas vezes
Substituo principalmente "null" por alguma variável que uso no controlador.
fonte
Embora já existam muitas respostas e um link para um artigo muito bom sobre detecção de alterações, eu queria dar meus dois centavos aqui. Acho que a verificação existe por um motivo, então pensei na arquitetura do meu aplicativo e percebi que as alterações na exibição podem ser tratadas usando
BehaviourSubject
o gancho do ciclo de vida correto. Então aqui está o que eu fiz para uma solução.Acabei recebendo a classe JavaScript subjacente e preciso inicializar meu próprio cabeçalho de calendário para o componente. Isso exige que o
ViewChild
arquivo seja renderizado antes que meu pai seja renderizado, e não é assim que o Angular funciona. É por isso que agrupei o valor necessário para o meu modelo emBehaviourSubject<View>(null)
:Em seguida, quando posso ter certeza de que a exibição está marcada, atualizo esse assunto com o valor de
@ViewChild
:Então, no meu modelo, eu apenas uso o
async
cachimbo. Sem hackers com detecção de alterações, sem erros, funciona sem problemas.Por favor, não hesite em perguntar se você precisa de mais detalhes.
fonte
Use um valor de formulário padrão para evitar o erro.
Em vez de usar a resposta aceita de aplicar detectChanges () em ngAfterViewInit () (que também resolveu o erro no meu caso), decidi salvar um valor padrão para um campo de formulário dinamicamente necessário, para que, quando o formulário for atualizado posteriormente, sua validade não será alterada se o usuário decidir alterar uma opção no formulário que acionaria os novos campos obrigatórios (e desativaria o botão de envio).
Isso economizou um pouquinho de código no meu componente e, no meu caso, o erro foi totalmente evitado.
fonte
this.cdr.detectChanges()
Eu recebi esse erro porque declarei uma variável e depois desejei
alterar seu valor usando
ngAfterViewInit
para corrigir que eu mudei de
para
fonte