Estou enfrentando o erro expression has changed after it was checked
. Sei que esta verificação só é executada no modo de desenvolvimento (executa duas vezes) e que não terei a mensagem de erro no modo de produção. Mas quero saber por que isso acontece.
Eu tenho um serviço de carregador baseado em sinal como este:
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class LoaderService {
private _isLoading = signal<boolean>(false);
get isLoading(): boolean {
return this._isLoading();
}
show() {
this._isLoading.update(() => true);
}
hide() {
this._isLoading.update(() => false);
}
}
Eu também tenho este interceptador:
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
HttpResponse,
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, catchError, map, throwError } from 'rxjs';
import { USE_LOADING_SPINNER } from '../constants/app.constants';
import { LoaderService } from '../../shared/services/loader.service';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(private loaderService: LoaderService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (req.context.get(USE_LOADING_SPINNER)) this.loaderService.show();
return next.handle(req).pipe(
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) this.loaderService.hide();
return event;
}),
catchError((error) => {
this.loaderService.hide();
return throwError(() => error);
})
);
}
}
O USE_LOADING_SPINNER
é sempre definido como verdadeiro, o que significa que tenho que marcar apenas as solicitações em que não quero ter nenhum indicador de carregamento.
Como o LoaderService
é baseado em sinal, registro um effect
no construtor de um componente como este:
constructor() {
effect(() => {
this.loading = this.loaderService.isLoading;
});
}
Observe que a loading
variável não é um sinal, é uma variável booleana pura, já que o isLoading
método retorna um valor booleano, não um sinal.
E no modelo eu tenho isso em um componente de grade:
[loading]="loading"
Esta configuração está funcionando. No roteamento inicial, o indicador de carregamento está sendo exibido.
Agora adiciono um método de atualização ao componente como este:
refresh() {
//this.loaderService.show();
this.gridData$ = this.userService.getUsers();
//.pipe(tap(() => this.loaderService.hide()));
}
Mas se eu clicar em atualizar, aparece o erro no título do tópico e o indicador de carregamento não aparece. O interceptador é acionado, eu verifiquei isso.
Mas se eu descomentar as chamadas, loaderService
ele funciona como esperado.
Por que recebo esse erro?
Espero que você entenda o que esse erro significa no caso comum de "configuração errada".
No seu caso, você provavelmente tem uma marcação
para corrigir isso, você deve transformar seu código para executar a chamada http durante o tratamento de eventos em vez de durante a execução do modelo. por exemplo, via rxjs
Acredito que o erro
expression has changed after it was checked
possa ser devido à atualizaçãoloading
após a inicialização da visualização. Em vez disso, opte por uma atualização baseada em sinal, que pode não gerar esse erro.Acredito que seja devido ao uso indevido de
getter
andsignal
, em vez de executar o sinal no nível de serviço, retornar o sinal real.Quando você quiser fazer algo com o estado anterior, use
update
, caso contrário set é uma opção melhor.Seu sinal é privado e você só quer retornar uma versão somente leitura do sinal, então usamos
asReadonly()
para remover as operações graváveisset
quandoupdate
o componente usa esse sinal.Agora, no nível do componente, em vez de ,
effect
o que é exagero, basta atribuir a propriedade de serviço a uma propriedade de componente.No nível do modelo, execute o sinal.