ExpressionChangedAfterItHasBeenCheckederror Explained
Proszę wyjaśnij mi dlaczego ciągle dostaję ten błąd: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Oczywiście, dostaję go tylko w trybie dev, nie dzieje się to na mojej kompilacji produkcyjnej, ale jest to bardzo denerwujące i po prostu nie rozumiem korzyści płynących z błędu w moim środowisku dev, który nie pojawi się na prod-prawdopodobnie z powodu mojego braku zrozumienia.
Zazwyczaj poprawka jest dość łatwa, po prostu zawijam kod powodujący błąd w setTimeout, Tak:
setTimeout(()=> {
this.isLoading = true;
}, 0);
Lub wymusić wykrycie zmian za pomocą konstruktor jak ten: constructor(private cd: ChangeDetectorRef) {}
:
this.isLoading = true;
this.cd.detectChanges();
Ale dlaczego ciągle napotykam ten błąd? Chcę to zrozumieć, żeby uniknąć tych hakerskich poprawek w przyszłości.
14 answers
Miałem podobny problem. Przeglądając dokumentację lifecycle hooks , zmieniłem ngAfterViewInit
na ngAfterContentInit
i zadziałało.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 04:24:24
Ten błąd wskazuje na prawdziwy problem w Twojej aplikacji, dlatego warto wyrzucić wyjątek.
In devMode
wykrywanie zmian dodaje dodatkowy obrót po każdym regularnym uruchomieniu wykrywania zmian, aby sprawdzić, czy Model się zmienił.
Jeśli model zmienił się między zwykłym i dodatkowym obrotem detekcji zmiany, oznacza to, że albo
- samo wykrywanie zmian spowodowało zmianę
- metoda lub getter zwraca inną wartość co czas nazywa się
Które są złe, ponieważ nie jest jasne, jak postępować, ponieważ model może nigdy się nie ustabilizować.
Jeśli kątowe biegi zmieniają detekcję, dopóki model się nie ustabilizuje, może działać w nieskończoność. Jeśli funkcja Angular nie uruchamia detekcji zmian, Widok może nie odzwierciedlać bieżącego stanu modelu.
Zobacz także Jaka jest różnica między trybem produkcji i rozwoju w Angular2?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:26
To bardziej na marginesie niż odpowiedź, ale może komuś pomóc. Natknąłem się na ten problem, próbując uzależnić obecność przycisku od stanu formularza:
<button *ngIf="form.pristine">Yo</button>
Z tego co wiem, ta składnia prowadzi do dodania i usunięcia przycisku z DOM na podstawie warunku. Co z kolei prowadzi do ExpressionChangedAfterItHasBeenCheckedError
.
Fix w moim przypadku (choć nie twierdzę, że rozumiem pełne konsekwencje różnicy), było użycie display: none
zamiast:
<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-01 07:06:46
Wiele zrozumienia przyszło, gdy zrozumiałemkątowe Haki cyklu życia i ich związek z wykrywaniem zmian.
Próbowałem uzyskać Angular, aby zaktualizować globalną flagę związaną z *ngIf
elementu, i próbowałem zmienić tę flagę wewnątrz ngOnInit()
Hooka cyklu życia innego komponentu.
Zgodnie z dokumentacją, metoda ta jest wywoływana po wykryciu zmian przez Angular:
Wywołany raz, po pierwszym ngOnChanges ().
Więc aktualizacja flagi wewnątrz ngOnChanges()
nie spowoduje wykrycia zmian. Następnie, po ponownym uruchomieniu wykrywania zmian, wartość flagi uległa zmianie I błąd jest wyrzucany.
W moim przypadku zmieniłem to:
constructor(private globalEventsService: GlobalEventsService) {
}
ngOnInit() {
this.globalEventsService.showCheckoutHeader = true;
}
Do tego:
constructor(private globalEventsService: GlobalEventsService) {
this.globalEventsService.showCheckoutHeader = true;
}
ngOnInit() {
}
I naprawił problem:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-11 21:52:18
W moim przypadku, miałem ten problem w moim pliku spec, podczas wykonywania moich testów.
I had to change ngIf
na [hidden]
<app-loading *ngIf="isLoading"></app-loading>
Do
<app-loading [hidden]="!isLoading"></app-loading>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-10 21:48:21
Miałem do czynienia z tym samym problemem, co zmiana wartości w jednej z tablic w moim komponencie. Ale zamiast wykrywania zmian przy zmianie wartości, zmieniłem strategię wykrywania zmian w komponencie na onPush
(która wykryje zmiany przy zmianie obiektu, a nie przy zmianie wartości).
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
selector: -
......
})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-12 22:40:11
Wykonaj poniższe kroki:
1. Użyj 'ChangeDetectorRef' importując go z @angular/core w następujący sposób:
import{ ChangeDetectorRef } from '@angular/core';
2. Zaimplementuj go w constructor () w następujący sposób:
constructor( private cdRef : ChangeDetectorRef ) {}
3. Dodaj następującą metodę do funkcji, którą wywołujesz podczas zdarzenia, takiego jak kliknięcie przycisku. Tak to wygląda:
functionName() {
yourCode;
//add this line to get rid of the error
this.cdRef.detectChanges();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-01 12:08:45
[[3]] nawiązując do artykułu https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
Tak więc mechanika wykrywania zmian faktycznie działa w taki sposób, że zarówno wykrywanie zmian, jak i weryfikacja są wykonywane synchronicznie. Oznacza to, że jeśli zaktualizujemy właściwości asynchronicznie, wartości nie będą aktualizowane, gdy uruchomiona zostanie pętla weryfikacji i nie otrzymamy błędu ExpressionChanged...
. Powód, dla którego my błąd ten polega na tym, że podczas procesu weryfikacji kątowy widzi różne wartości, a następnie to, co zarejestrował podczas fazy wykrywania zmian. Żeby tego uniknąć....
1) Użyj changeDetectorRef
2) Użyj setTimeOut. Spowoduje to wykonanie kodu w innej maszynie wirtualnej jako makro-zadanie. Angular nie zobaczy tych zmian podczas procesu weryfikacji i nie otrzymasz tego błędu.
setTimeout(() => {
this.isLoading = true;
});
3) jeśli naprawdę chcesz wykonać swój kod na tej samej maszynie wirtualnej użyj np.
Promise.resolve(null).then(() => this.isLoading = true);
To stworzy mikro-zadanie. Kolejka mikro-zadań jest przetwarzana po zakończeniu wykonywania bieżącego kodu synchronicznego, dlatego aktualizacja do właściwości nastąpi po etapie weryfikacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-12 21:55:13
Miałem tego rodzaju błąd w Ionic3(który używa Angular 4 jako części stosu technologii).
Dla mnie to było to:
<ion-icon [name]="getFavIconName()"></ion-icon>
Więc próbowałem warunkowo zmienić typ ion-icon z pin
na remove-circle
, w zależności od trybu, na którym działał ekran.
Zgaduję, że będę musiał zamiast tego dodać *ngIF.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-18 17:58:08
Dla mojego problemu, czytałem github - "ExpressionChangedAfterItHasBeenCheckederror podczas zmiany wartości komponentu' non model 'w afterViewInit" i zdecydowałem się dodać ngModel
<input type="hidden" ngModel #clientName />
To naprawiło mój problem, mam nadzieję, że komuś pomoże.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-13 14:57:31
Oto moje przemyślenia na temat tego, co się dzieje. Nie przeczytałem dokumentacji, ale jestem pewien, że jest to część tego, dlaczego wyświetlany jest błąd.
*ngIf="isProcessing()"
Podczas używania *ngIf, fizycznie zmienia DOM, dodając lub usuwając element za każdym razem, gdy zmienia się warunek. Jeśli więc warunek zmieni się zanim zostanie renderowany do widoku (co jest wysoce możliwe w świecie Angular), błąd zostanie wyrzucony. Zobacz Wyjaśnienie tutaj pomiędzy trybami rozwoju i produkcji.
[hidden]="isProcessing()"
Kiedy użycie [hidden] nie zmienia fizycznie DOM, a jedynie ukrywa element przed widokiem, najprawdopodobniej używając CSS z tyłu. Element nadal znajduje się w DOM, ale nie jest widoczny w zależności od wartości warunku. Dlatego błąd nie wystąpi podczas używania [hidden].
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-07 03:55:25
@HostBinding
może być mylące źródło tego błędu.
Na przykład, powiedzmy, że masz następujące powiązanie hosta w komponencie
// image-carousel.component.ts
@HostBinding('style.background')
style_groupBG: string;
Dla uproszczenia, powiedzmy, że ta właściwość jest aktualizowana za pomocą następującej właściwości wejściowej:
@Input('carouselConfig')
public set carouselConfig(carouselConfig: string)
{
this.style_groupBG = carouselConfig.bgColor;
}
W komponencie nadrzędnym ustawiasz go programowo w ngAfterViewInit
@ViewChild(ImageCarousel) carousel: ImageCarousel;
ngAfterViewInit()
{
this.carousel.carouselConfig = { bgColor: 'red' };
}
Oto co się dzieje:
- tworzony jest komponent nadrzędny
- komponent ImageCarousel jest tworzony i przypisywany do
carousel
(via ViewChild) - nie możemy uzyskać dostępu
carousel
dopókingAfterViewInit()
(będzie null) - przypisujemy konfigurację, która ustawia
style_groupBG = 'red'
To z kolei ustawia - ten komponent jest 'własnością' twojego komponentu nadrzędnego, więc kiedy sprawdza zmiany, znajduje zmianę na
carousel.style.background
i nie jest wystarczająco sprytny, aby wiedzieć, że nie jest to problem, więc rzuca wyjątek.
background: red
na komponencie hosta ImageCarousel
Jednym z rozwiązań jest wprowadzenie innego wrappera div insider ImageCarousel i ustaw na nim kolor tła, ale wtedy nie uzyskasz niektórych korzyści z używania HostBinding
(takich jak umożliwienie rodzicowi kontrolowania pełnych granic obiektu).
Lepszym rozwiązaniem, w komponencie nadrzędnym jest dodanie detectChanges () po ustawieniu konfiguracji.
ngAfterViewInit()
{
this.carousel.carouselConfig = { ... };
this.cdr.detectChanges();
}
To może wyglądać dość oczywiste i bardzo podobne do innych odpowiedzi, ale jest subtelna różnica.
Rozważ przypadek, w którym nie dodasz @HostBinding
dopóki później podczas rozwoju. Nagle pojawia się ten błąd i wydaje się, że nie ma to żadnego sensu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-02 21:01:21
Wskazówki debugowania
Ten błąd może być dość mylący i łatwo jest przyjąć błędne założenie o tym, kiedy dokładnie się pojawia. Uważam, że pomocne jest dodanie wielu instrukcji debugowania, takich jak to, w całym dotkniętych komponentach w odpowiednich miejscach. Pomaga to zrozumieć przepływ.
W rodzicu umieść instrukcje takie jak to (dokładny łańcuch 'EXPRESSIONCHANGED' jest ważny), ale poza tym są to tylko przykłady:
console.log('EXPRESSIONCHANGED - HomePageComponent: constructor');
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config', newConfig);
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config ok');
console.log('EXPRESSIONCHANGED - HomePageComponent: running detectchanges');
In the child / services / wywołania timera:
console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');
Jeśli uruchomisz detectChanges
ręcznie dodaj również logowanie:
console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
this.cdr.detectChanges();
Następnie w Debuggerze Chrome po prostu filtruj przez 'EXPRESSIONCHANGES'. Pokaże Ci dokładnie przepływ i kolejność wszystkiego, co zostanie ustawione, a także dokładnie w jakim punkcie kątowym rzuca błąd.
Możesz również kliknąć szare linki, aby umieścić punkty przerwania.
Kolejna rzecz, na którą należy uważać, jeśli masz podobne właściwości w całym swoim aplikacja (taka jak style.background
) Upewnij się, że debugujesz tę, którą myślisz , ustawiając ją na niejasną wartość koloru.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-02 21:19:58
Mój problem był oczywisty, kiedy dodałem *ngIf
, ale to nie była przyczyna. Błąd był spowodowany zmianą modelu w znacznikach {{}}
, a następnie próbą wyświetlenia zmienionego modelu w instrukcji *ngIf
później. Oto przykład:
<div>{{changeMyModelValue()}}</div> <!--don't do this! or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">{{myModel.value}}</div>
Aby Rozwiązać problem, zmieniłem miejsce, w którym wywołałem changeMyModelValue () na miejsce, które miało więcej sensu.
W mojej sytuacji chciałem changeMyModelValue() wywoływać zawsze, gdy komponent potomny zmieni dane. To wymagane tworzę i emituję Zdarzenie w komponent potomny, więc rodzic mógł go obsłużyć (przez wywołanie changeMyModelValue (). zobacz https://angular.io/guide/component-interaction#parent-listens-for-child-event
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-11 18:50:50