Wyrażenie ExpionChangedAfterItHasBeenCheckedError


308

Wyjaśnij mi, dlaczego wciąż pojawia się ten błąd: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.

Oczywiście dostaję to tylko w trybie deweloperskim, nie dzieje się to w mojej wersji produkcyjnej, ale jest to bardzo denerwujące i po prostu nie rozumiem korzyści płynących z błędu w moim środowisku programistycznym, który nie pojawia się w prod - -prawdopodobnie z powodu mojego braku zrozumienia.

Zwykle poprawka jest dość łatwa, po prostu zawijam błąd powodujący kod w setTimeout w następujący sposób:

setTimeout(()=> {
    this.isLoading = true;
}, 0);

Lub wymuś wykrywanie zmian za pomocą takiego konstruktora constructor(private cd: ChangeDetectorRef) {}:

this.isLoading = true;
this.cd.detectChanges();

Ale dlaczego ciągle mam ten błąd? Chcę to zrozumieć, aby w przyszłości uniknąć tych niepotrzebnych poprawek.


Odpowiedzi:


121

Miałem podobny problem. Patrząc na dokumentacji haczykami cyklu życia , zmieniłem ngAfterViewInitsię ngAfterContentIniti to zadziałało.


@PhilipEnc mój problem był związany ze zmianą wywołaną przez zmianę DOM. Gdy DOM się zmieni, obiekt QueryList (pochodzący z właściwości @ContentChildren) zostanie zaktualizowany, a metoda, którą nazwała aktualizacja, zmieniła właściwość dwukierunkową. To stworzyło problem, który miałem. Otworzenie tej zmiany do dwóch właściwości z setTimeoutpokazanym wyżej sposobem załatwiło sprawę. Dzięki!
kbpontius

1
W moim przypadku umieściłem kod, który zmienił wartość tablicy siatki primeng w ngAfterContentInit, umieściłem kod w ngOnInit i zadziałało.
Vibhu

ngAfterContentCheckeddziała tutaj, podczas gdy ngAfterContentInitwciąż zgłasza błąd.
ashubuntu

Zastosowanie ngAfterContentChecked, ale projekt ładowany bardzo wolno
Ghotekar Rahul

101

Ten błąd wskazuje na prawdziwy problem w Twojej aplikacji, dlatego sensowne jest zgłoszenie wyjątku.

W devModezmianie wykrywanie dodaje dodatkową turę po każdym biegu regularnego wykrywania zmian, by sprawdzić, czy model się nie zmieniło.

Jeśli model zmienił się między zwykłym a dodatkowym zakrętem wykrywania zmian, oznacza to, że albo

  • samo wykrycie zmiany spowodowało zmianę
  • metoda lub getter zwraca inną wartość przy każdym wywołaniu

które są złe, ponieważ nie jest jasne, jak postępować, ponieważ model może nigdy się nie ustabilizować.

Jeśli wykrywanie kątowe zmienia się, dopóki model się nie ustabilizuje, może działać wiecznie. Jeśli Angular nie uruchomi wykrywania zmian, widok może nie odzwierciedlać bieżącego stanu modelu.

Zobacz także Jaka jest różnica między trybem produkcyjnym a programistycznym w Angular2?


4
Jak mogę uniknąć tego błędu w przyszłości? Czy jest inny sposób myślenia o kodzie, aby nie popełniać tych samych błędów?
Kevin LeStarge

25
Zwykle jest to spowodowane niektórymi wywołaniami cyklu życia, takimi jak ngOnInitlub ngOnChangesmodyfikacja modelu (niektóre wywołania cyklu życia pozwalają modyfikować model, inni tego nie robią, sam nie pamiętam, które dokładnie robią, czy nie). Nie łącz się z metodami lub funkcjami w widoku, zamiast tego łącz się z polami i aktualizuj pola w procedurach obsługi zdarzeń. Jeśli musisz powiązać metody, upewnij się, że zawsze zwracają tę samą instancję wartości, o ile w rzeczywistości nie nastąpiła zmiana. Wykrywanie zmian wywoła te metody bardzo często.
Günter Zöchbauer

Dla każdego przybywającego tutaj, który otrzyma ten błąd przy użyciu biblioteki ngx-toaster, oto raport o błędzie: github.com/scttcper/ngx-toastr/issues/160
rmcsharry 24.09.17

2
Niekoniecznie jest to problem z aplikacją. Fakt, że wywołanie changeRef.detectChanges()jest rozwiązaniem / tłumi błąd, jest tego dowodem. To jest jak zmiana stanu wewnątrz $scope.$watch()Angulara 1.
Kevin Beal

1
Nie znam zbyt dobrze Angulara 1, ale wykrywanie zmian w Angularu 2 działa zupełnie inaczej. Masz rację, że niekoniecznie jest to problem, ale zwykle cdRef.detectChanges()jest konieczny tylko w niektórych dziwnych przypadkach i powinieneś uważnie patrzeć, kiedy potrzebujesz, aby dobrze zrozumieć, dlaczego.
Günter Zöchbauer

83

Dużo zrozumienia przyszło, gdy zrozumiałem Haki Angular Lifecycle i ich związek z wykrywaniem zmian.

Próbowałem przekonać Angulara do zaktualizowania flagi globalnej powiązanej *ngIfz elementem i próbowałem zmienić tę flagę wewnątrz ngOnInit()haka cyklu życia innego komponentu.

Zgodnie z dokumentacją ta metoda jest wywoływana po wykryciu zmian przez Angulara:

Wywoływany raz, po pierwszym ngOnChanges ().

Tak więc aktualizacja flagi wewnątrz ngOnChanges()nie zainicjuje wykrywania zmian. Następnie, gdy wykrycie zmiany zostanie ponownie naturalnie uruchomione, wartość flagi zmieniła się i błąd zostanie zgłoszony.

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 :)


3
Mój problem był podobny. Że popełniłem błąd po wielu godzinach i zdefiniowałem zmienną poza funkcją i konstruktorem ngOnInit. To odbiera zmiany danych z obserwowalnego, który jest umieszczony w funkcji inicjalizacji. Zrobiłeś to samo co ty, aby naprawić błąd.
ravo10

1
Bardzo podobne dookoła, ale próbowałem przewijać ( router.navigate) po załadowaniu do fragmentu, jeśli jest obecny w adresie URL. Ten kod został początkowo umieszczony w miejscu, w AfterViewInitktórym otrzymywałem błąd, a potem przeniosłem się, jak mówisz do konstruktora, ale nie respektował fragmentu. Przeprowadzka do ngOnInitrozwiązania :) dzięki!
Joel Balmer

Co się stanie, jeśli mój html zostanie powiązany z czasem zwracającym getter jako „HH: MM” przez get ClockValue () {return DateTime.TimeAMPM (new Date ())} w końcu wyłączy się, gdy zmieni się minuta podczas wykrywania, jak mogę napraw to?
Meryan

To samo tutaj. Stwierdzono również, że zawijanie do setInterval()działa również wtedy, gdy musi zostać uruchomiony po innym kodzie zdarzenia dożywotniego.
Rick Strahl

39

Aktualizacja

Zdecydowanie polecam zacząć od samooceny PO w pierwszej kolejności: właściwie zastanów się, co można zrobić w constructorporównaniu z tym, co należy zrobić ngOnChanges().

Oryginalny

To jest raczej notatka poboczna 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>

O ile mi wiadomo, ta składnia prowadzi do dodawania i usuwania przycisku z DOM na podstawie warunku. Co z kolei prowadzi do ExpressionChangedAfterItHasBeenCheckedError.

Poprawką w moim przypadku (chociaż nie twierdzę, że rozumiem pełne implikacje różnicy) było użycie display: nonezamiast tego:

<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>

6
Rozumiem różnicę między ngIf a stylem, że ngIf nie zawiera HTML na stronie, dopóki warunek nie jest spełniony, tym samym nieco zmniejszając „wagę strony”, podczas gdy technika stylu powoduje, że HTML zawsze jest na stronie i jest po prostu ukryty lub pokazany na podstawie wartości form.pristine.
user3785010

4
Równie dobrze możesz użyć [hidden]zamiast bardzo pełnej [style.display]części. :)
Philipp Meissner,

2
Dlaczego nie. Chociaż, jak wspomniano w @Simon_Weaver w innym komentarzu na tej stronie, [hidden] nie zawsze będzie miało takie samo zachowanie jakdisplay: none
Arnaud P

1
Pokazałem dwa różne przyciski (wylogowanie / logowanie) z * ngIf w każdym przycisku i to spowodowało problem.
GoTo

konstruktor był dla mnie właściwym miejscem, wprowadzając materialny bar przekąskowy
austin

31

Były ciekawe odpowiedzi, ale nie znalazłem takiej, która pasowałaby do moich potrzeb, najbliższa z @ chittrang-mishra, która odnosi się tylko do jednej konkretnej funkcji, a nie kilku przełączników jak w mojej aplikacji.

Nie chciałem [hidden]skorzystać z *ngIftego, że nie jestem nawet częścią DOM, więc znalazłem następujące rozwiązanie, które może nie być najlepsze dla wszystkich, ponieważ pomija błąd zamiast go poprawiać, ale w moim przypadku, w którym znam końcowy wynik jest poprawny, wydaje się być odpowiedni dla mojej aplikacji.

To, co zrobiłem, to wdrożenie AfterViewChecked, dodanie, constructor(private changeDetector : ChangeDetectorRef ) {}a następnie

ngAfterViewChecked(){
  this.changeDetector.detectChanges();
}

Mam nadzieję, że to pomaga innym, podobnie jak wielu innym.


3
czy to nie uruchomi pętli wykrywania nieskończonej zmiany? to znaczy, wykrywasz zmiany po sprawdzeniu.
Manuel Azar

@ManuelAzar Najwyraźniej nie. To jest jedyne rozwiązanie, które działało dla mnie. OSTATNIE trochę ciszy w mojej konsoli. Byłem tak zmęczony tymi wszystkimi „błędami” wykrywania nieistotnych zmian.
Jeremy Thille

31

Wykrywanie zmian przebiegów kątowych, a gdy okaże się, że niektóre wartości, które zostały przekazane do komponentu potomnego, zostały zmienione, kątowy zgłasza błąd:

ExpressionChangedAfterItHasBeenCheckedError kliknij po więcej

Aby to naprawić, możemy użyć AfterContentChecked haka cyklu życia i

import { ChangeDetectorRef, AfterContentChecked} from '@angular/core';

  constructor(
  private cdref: ChangeDetectorRef) { }

  ngAfterContentChecked() {

    this.cdref.detectChanges();

  }

Chociaż może to rozwiązać problem, czy nie jest to zbyt rozbudowane i nadmierne zabijanie dysku CD?
Nicky

Myślę, że to jedyna odpowiedź, która rozwiązuje ten błąd spowodowany przekazaniem wartości do dziecka. Dzięki!
java-addict301

@Nicky Tak. Za każdym razem, gdy dotykasz ekranu, wywoływana jest funkcja ngAfterContentChecked ()
Mert Mertce,

25

W moim przypadku miałem ten problem w pliku specyfikacji podczas uruchamiania testów.

Musiałem się zmienić ngIf na [hidden]

<app-loading *ngIf="isLoading"></app-loading>

do

<app-loading [hidden]="!isLoading"></app-loading>


2
Różnica polega na tym, że *ngIfzmienia DOM, dodając i usuwając element ze strony, a jednocześnie [hidden]zmienia widoczność elementu, nie usuwając go z DOM.
Grungondola

5
Ale to tak naprawdę nie naprawiło prawdziwego problemu ...?
ravo10

23

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 konstruktorze () w następujący sposób:

constructor(   private cdRef : ChangeDetectorRef  ) {}

3. Dodaj następującą metodę do funkcji, którą wywołujesz w przypadku zdarzenia, takiego jak kliknięcie przycisku. Wygląda to tak:

functionName() {   
    yourCode;  
    //add this line to get rid of the error  
    this.cdRef.detectChanges();     
}

23

Ja pomocą NG2-carouselamos (kąt 8 i bootstrap 4)

Poniżej naprawiłem mój problem:

Co ja zrobiłem:

1. implement AfterViewChecked,  
2. add constructor(private changeDetector : ChangeDetectorRef ) {} and then 
3. ngAfterViewChecked(){ this.changeDetector.detectChanges(); }

Pomogło. Niesamowity!!
Pathik Vejani

Uratowałeś mi dzień ... Dzięki!
omostan

19

Napotkałem ten sam problem, ponieważ wartość zmieniała się w jednej z tablic mojego komponentu. Ale zamiast wykrywać zmiany związane ze zmianą wartości, zmieniłem strategię wykrywania zmian składników na onPush(która wykryje zmiany związane ze zmianą obiektu, a nie ze zmianą wartości).

import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';

@Component({
    changeDetection: ChangeDetectionStrategy.OnPush
    selector: -
    ......
})

Wydawało się, że działa to dynamicznie dodając / usuwając elementy sterujące. Czy są jakieś wady?
Ricardo Saracino,

Działa jak urok w sytuacji, którą mam pod ręką, dzięki! Komponent został powiązany z „globalnym” obiektem, który został zmieniony w innym miejscu i spowodował wystąpienie błędu. Ten komponent miał już moduł obsługi aktualizacji, gdy obiekt powiązany był aktualizowany, ten moduł obsługi zdarzeń wywołuje teraz changeDetectorRef.detectChanges () w połączeniu z ChangeDetectionStrategy.OnPush. Działa to zgodnie z wymaganiami bez błędu.
Bernoulli IT,

@RicardoSaracino, czy znalazłeś jakieś wady? Zastanawiałem się nad tym samym. Wiem, jak działa OnPush z wykrywaniem zmian, ale zastanawiam się, czy istnieje problem, którego może brakuje. Nie chce mi się kręcić.
mtpultz

@RicardoSaracino, tak to ma pewne wady, można odnieść to szczegółowe powiązanie blog.angular-university.io/onpush-change-detection-how-it-works
Dheeraj

@BernoulliIT Dzięki, cieszę się, że ci się udało.
Dheeraj

17

Odnosząc się do artykułu https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4

Tak więc mechanika wykrywania zmian działa w taki sposób, że zarówno wykrywanie zmian, jak i podsumowania weryfikacji są wykonywane synchronicznie. Oznacza to, że jeśli zaktualizujemy właściwości asynchronicznie, wartości nie zostaną zaktualizowane podczas działania pętli weryfikacyjnej i nie wystąpi ExpressionChanged...błąd. Przyczyną tego błędu jest to, że podczas procesu weryfikacji Angular widzi inne wartości niż to, co zarejestrował podczas fazy wykrywania zmiany. Aby tego uniknąć ...

1) Użyj changeDetectorRef

2) użyj setTimeOut. Spowoduje to wykonanie kodu na innej maszynie wirtualnej jako makropolecenie. Angular nie zobaczy tych zmian podczas procesu weryfikacji i nie pojawi się ten błąd.

 setTimeout(() => {
        this.isLoading = true;
    });

3) Jeśli naprawdę chcesz wykonać swój kod na tej samej maszynie wirtualnej, użyj jak

Promise.resolve(null).then(() => this.isLoading = true);

To stworzy mikro-zadanie. Kolejka mikroprocesorów jest przetwarzana po zakończeniu wykonywania bieżącego kodu synchronicznego, dlatego aktualizacja właściwości nastąpi po kroku weryfikacji.


Czy możesz użyć opcji nr 3 z wyrażeniem stylu? Mam wyrażenie stylu dla wysokości, które powinno być ocenione jako ostatnie, ponieważ jest oparte na wstrzykiwanej treści.
N-ate

1
Przepraszam, właśnie widziałem Twój komentarz, tak, nie widzę żadnego powodu, dlaczego nie. To powinno działać również ze zmianami stylu.
ATHER

4

@HostBinding może być mylącym źródłem tego błędu.

Załóżmy na przykład, że masz następujące powiązanie hosta w komponencie

// image-carousel.component.ts
@HostBinding('style.background') 
style_groupBG: string;

Dla uproszczenia załóżmy, ż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 programujesz go programowo ngAfterViewInit

@ViewChild(ImageCarousel) carousel: ImageCarousel;

ngAfterViewInit()
{
    this.carousel.carouselConfig = { bgColor: 'red' };
}

Oto co się dzieje:

  • Twój komponent nadrzędny został utworzony
  • Składnik ImageCarousel jest tworzony i przypisywany carousel(przez ViewChild)
  • Nie możemy uzyskać dostępu carouseldo ngAfterViewInit()(będzie zerowy)
  • Przypisujemy konfigurację, która ustawia style_groupBG = 'red'
  • To z kolei ustawia background: redskładnik Host ImageCarousel
  • Ten komponent jest „własnością” komponentu nadrzędnego, więc gdy sprawdza zmiany, znajduje zmianę carousel.style.background i nie jest wystarczająco sprytny, aby wiedzieć, że nie jest to problem, więc zgłasza wyjątek.

Jednym z rozwiązań jest wprowadzenie kolejnej owiniętej okładki ImageCarousel i ustawienie na niej koloru 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 funkcji wykrywaniaChanges () po ustawieniu konfiguracji.

ngAfterViewInit()
{
    this.carousel.carouselConfig = { ... };
    this.cdr.detectChanges();
}

Może to wyglądać dość oczywiste w ten sposób i bardzo podobne do innych odpowiedzi, ale istnieje subtelna różnica.

Rozważ przypadek, gdy nie dodasz go @HostBindingpóźniej podczas programowania. Nagle pojawia się ten błąd i wydaje się, że nie ma to żadnego sensu.


2

Oto moje przemyślenia na temat tego, co się dzieje. Nie przeczytałem dokumentacji, ale jestem pewien, że jest to część powodu, dla którego wyświetlany jest błąd.

*ngIf="isProcessing()" 

Gdy używasz * 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 wyświetlony w widoku (co jest wysoce możliwe w świecie Angulara), błąd zostanie zgłoszony. Patrz wyjaśnienia tutaj między trybami rozwoju i produkcji.

[hidden]="isProcessing()"

Podczas używania [hidden]nie zmienia fizycznie, DOMale jedynie ukrywa elementwidok, najprawdopodobniej używając CSSz tyłu. Element jest nadal obecny w DOM, ale niewidoczny w zależności od wartości warunku. Dlatego błąd nie wystąpi podczas używania [hidden].


Jeśli isProcessing()robi się coś ame, należy użyć !isProcessing()dla[hidden]
Matthieu Charbonnier

hidden„nie używa CSS z tyłu”, to zwykła właściwość HTML. developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/…
Lazar Ljubenović

1

W przypadku mojego problemu czytałem github - „ExpressionChangedAfterItHasBeenCheckedError podczas zmiany wartości składnika„ nie modelowego ”w afterViewInit” i postanowiłem dodać model ngModel

<input type="hidden" ngModel #clientName />

Naprawił mój problem, mam nadzieję, że komuś pomoże.


1
Gdzie na tej stronie jest napisane, aby dodać ngModel. Czy możesz wyjaśnić, dlaczego to powinno być pomocne?
Peter Wippermann

Kiedy śledziłem ten problem, postanowiłem zbadać link. Po przeczytaniu artykułu dodałem atrybut i naprawiłem mój problem. Jest to pomocne, jeśli ktoś napotka ten sam problem.
Demodave,

1

Wskazówki dotyczące debugowania

Ten błąd może być dość mylący i łatwo jest błędnie założyć, kiedy dokładnie się pojawia. Przydaje mi się dodawanie wielu takich instrukcji debugowania do odpowiednich komponentów w odpowiednich miejscach. Pomaga to zrozumieć przepływ.

W rodzicu umieść takie instrukcje (dokładny ciąg „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');

W wywołaniach potomnych / usługach / odliczaniu czasu:

    console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
    console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');

Jeśli uruchomisz detectChangesręcznie, dodaj również rejestrowanie:

    console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
    this.cdr.detectChanges();

Następnie w debuggerze Chrome po prostu filtruj według „ZMIANY WYRAŻANIA”. To pokaże dokładnie przepływ i kolejność wszystkiego, co zostanie ustawione, a także dokładnie w którym momencie Angular zgłasza błąd.

wprowadź opis zdjęcia tutaj

Możesz także kliknąć szare linki, aby wstawić punkty przerwania.

Kolejną rzeczą, na którą należy zwrócić uwagę, jeśli masz podobnie nazwane właściwości w swojej aplikacji (np. style.background), Upewnij się, że debugujesz tę, o której myślisz - ustawiając ją na niejasną wartość koloru.


1

W moim przypadku miałem właściwość asynchroniczną LoadingServicez obiektem BehaviouralSubjectisLoading

Korzystanie z [ukrytego] modelu działa, ale * ngIf zawiedzie

    <h1 [hidden]="!(loaderService.isLoading | async)">
        THIS WORKS FINE
        (Loading Data)
    </h1>

    <h1 *ngIf="!(loaderService.isLoading | async)">
        THIS THROWS ERROR
        (Loading Data)
    </h1>

1

Rozwiązanie, które działało dla mnie przy użyciu rxjs

import { startWith, tap, delay } from 'rxjs/operators';

// Data field used to populate on the html
dataSource: any;

....

ngAfterViewInit() {
  this.yourAsyncData.
      .pipe(
          startWith(null),
          delay(0),
          tap((res) => this.dataSource = res)
      ).subscribe();
}

jaki był problematyczny kod? jakie jest tutaj rozwiązanie?
mkb

Cześć @mkb problem polegał na tym, ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.że zmiany wartości są wyzwalane, gdy zmienia się DOM
Sandeep K Nair

Cześć, mam na myśli to, co zrobiłeś tutaj, aby rozwiązać problem. W ogóle nie używałeś rxjs ani nie dodałeś opóźnienia (), ani dodałeś startWith ()? Już używam rxjs z różnymi metodami rxjs, ale nadal pojawia się błąd, mam nadzieję rozwiązać zagadkę :(
mkb

Dodane delaysprawiają, że błąd zniknie. Działa podobnie do setTimeout.
Lazar Ljubenović

1

Miałem tego rodzaju błąd w Ionic3 (który używa Angulara 4 jako części stosu technologii).

Dla mnie robił to:

<ion-icon [name]="getFavIconName()"></ion-icon>

Próbowałem więc warunkowo zmienić typ ikony jonowej z a pinna aremove-circle , za trybie ekran działał dalej.

Chyba będę musiał dodać *ngIfzamiast tego.


1

Mój problem pojawił się, gdy dodałem, *ngIfale to nie była przyczyna. Błąd został spowodowany przez zmianę modelu w {{}}znacznikach, a następnie próbę wyświetlenia zmienionego modelu w *ngIfinstrukcji 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 dzwoniłem changeMyModelValue() do miejsca, które ma większy sens.

W mojej sytuacji chciałem changeMyModelValue()zadzwonić, ilekroć element podrzędny zmienił dane. Wymagało to utworzenia i emisji zdarzenia w komponencie potomnym, aby rodzic mógł go obsłużyć (dzwoniąc changeMyModelValue(). Patrz https://angular.io/guide/component-interaction#parent-listens-for-child-event


0

Mam nadzieję, że to pomoże komuś, kto tu przyjdzie: Wykonujemy zgłoszenia serwisowe w ngOnInitnastępujący sposób i używamy zmiennej displayMaindo kontrolowania montażu elementów w DOM.

component.ts

  displayMain: boolean;
  ngOnInit() {
    this.displayMain = false;
    // Service Calls go here
    // Service Call 1
    // Service Call 2
    // ...
    this.displayMain = true;
  }

i component.html

<div *ngIf="displayMain"> <!-- This is the Root Element -->
 <!-- All the HTML Goes here -->
</div>

0

Wystąpił ten błąd, ponieważ korzystałem ze zmiennej w pliku component.html, która nie została zadeklarowana w pliku component.ts. Po usunięciu części w HTML błąd zniknął.


0

Wystąpił ten błąd, ponieważ wysyłałem akcje redux w trybie modalnym, a modal nie został w tym czasie otwarty. Wysyłałem akcje w chwili, gdy składnik modalny otrzymuje dane wejściowe. Dlatego umieściłem tam setTimeout, aby upewnić się, że modal jest otwarty, a następnie akcje są wysyłane.


0

Dla każdego, kto ma z tym problem. Oto sposób prawidłowego debugowania tego błędu: https://blog.angular-university.io/angular-debugging/

W moim przypadku rzeczywiście pozbyłem się tego błędu, używając tego [ukrytego] hacka zamiast * ngIf ...

Ale link I, pod warunkiem pozwoliło mi znaleźć winnego * ngIf :)

Cieszyć się.


Używanie hiddenzamiast ngIfhakowania nie rozwiązuje w ogóle sedna problemu. Po prostu maskujesz problem.
Lazar Ljubenović

-2

Rozwiązanie ... usługi i rxjs ... emitery zdarzeń i wiązanie właściwości używają rxjs .. lepiej jest wdrożyć to samo, więcej kontroli, łatwiej debugować. Pamiętaj, że emitery zdarzeń używają rxjs. Po prostu stwórz usługę i obserwuj, aby każdy komponent zasubskrybował obserwatora i albo przekaż nową wartość, albo wartość cosume w razie potrzeby


1
Nie tylko to nie odpowiada na pytanie, ale także okropna rada. Chłopaki, proszę nie reimplementuj rxjs tylko dlatego, że otrzymujesz błędy CD Angulara. :)
Lazar Ljubenović
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.