Angular: ExpressionChangedAfterItHasBeenCheckedError: Der Ausdruck wurde geändert, nachdem er in ng 4 überprüft wurde

Erstellt am 16. Juni 2017  ·  201Kommentare  ·  Quelle: angular/angular

Ich reiche ein ...


[ ] Regression (behavior that used to work and stopped working in a new release)
[X ] Bug report #14748 
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Aktuelles Verhalten


Nachdem ich ein beobachtbares Objekt in meiner Vorlage mit Async verwendet habe, erhalte ich Folgendes:
FEHLER Fehler: ExpressionChangedAfterItHasBeenCheckedError: Der Ausdruck wurde geändert, nachdem er überprüft wurde. Vorheriger Wert: ''. Aktueller Wert: 'etwas'

Erwartetes Verhalten

Bitte erzählen Sie uns etwas über Ihre Umgebung

<br i="15"/>
Angular version: 4.2.2

<p i="16">Browser:</p>

<ul i="17">
<li i="18">[X] Chrome (desktop) version Version 58.0.3029.110 (64-bit)</li>
</ul>

<p i="19">For Tooling issues:</p>

<ul i="20">
<li i="21">Node version: v6.10.3</li>
<li i="22">Platform: Mac</li>
</ul>
core regression bufix

Hilfreichster Kommentar

Ich bekomme das gleiche Problem nach dem Upgrade von 4.1.3 auf 4.2.3. Die Verwendung von setTimeout behebt das Problem.

von:

PanictUtil.getRequestObservable (). Subscribe (data => this.requesting = data);

zu:

PanictUtil.getRequestObservable (). Subscribe (data => setTimeout (() => this.requesting = data, 0));

Alle 201 Kommentare

Hatte das gleiche Problem mit der Verwendung von Redux. Hier ist ein Link zu dem Problem, das ich in ihrem Repository gepostet habe. Wenn auf Winkel 2 keine Fehler vorliegen, aber auf Winkel 4.2.2 wird der Ausdruck geändert, nachdem Fehler überprüft wurden.
https://github.com/angular-redux/store/issues/428

Das Problem tritt bei meinen Komponenten auf, wenn ich von 4.1.3 auf 4.2.x stoße. Das Zurücksetzen auf 4.1.3 behebt das Problem für mich, aber das möchte ich nicht für immer behalten.

Ich könnte auf einem minimalen Projekt reproduzieren, ich versuche immer noch herauszufinden, wie diese (vielleicht) Regression behoben werden kann. Aber es sieht so aus, als ob der Dirty Check in dev erzwungen wurde. Modus von 4.2.x. Aber das Changelog ist darüber nicht klar. Jeder Tipp willkommen.

Ich bekomme das gleiche Problem nach dem Upgrade von 4.1.3 auf 4.2.3. Die Verwendung von setTimeout behebt das Problem.

von:

PanictUtil.getRequestObservable (). Subscribe (data => this.requesting = data);

zu:

PanictUtil.getRequestObservable (). Subscribe (data => setTimeout (() => this.requesting = data, 0));

@jingglang Könnten Sie bitte versuchen, das Problem auf http://plnkr.co/edit/tpl : AvJOMERrnz94ekVua0u5 mit so wenig Code wie möglich zu reproduzieren?

Ich bekomme das gleiche Problem - ein Upgrade von 2.4 auf 4.2, und ein Teil meiner Versteck- / Einblendlogik ist jetzt fehlerhaft. Es handelt sich um eine Logik im Akkordeonstil, bei der die Sichtbarkeit vom Vergleich des aktuellen Panels mit einem Observable abhängt, das angibt, welches Panel (unter anderem) sichtbar sein soll. Die Komponente verwendet @select , um das Observable

Ich bekomme das gleiche Problem, wenn 4.1.3 auf 4.2.2 aktualisiert wird.

Aber ich habe eine Problemumgehung gefunden.
Injektion von ChangeDetectionRef und Aufruf der Funktion detectionChanges() an der Fehlerstelle.

constructor(private cdr: ChangeDetectionRef) {
}

onChange(): void {
  this.val += 1; // <- get error after
  this.cdr.detectionChanges();
}

Ich denke, dies ist ein Problem mit der folgenden Änderung in 4.2.

https://github.com/angular/angular/pull/16592

So beheben Sie dieses Problem: https://github.com/angular/angular/issues/14321

Haben Sie Inhalte in einem ng-content -Tag?

Ich habe das gleiche Problem mit einem Formular in einem ng-content -Tag, das jetzt mit dem ContentChangedAfter-Fehler fehlerhaft ist.

Ich bekomme das gleiche Problem, wenn 4.1.3 auf 4.2.0 oder höher aktualisiert wird

Ich füge ein kleines Projekt hinzu, um den Fehler zu reproduzieren

app-error.zip

Im Anschluss habe ich ein Downgrade auf 4.1.3 durchgeführt (wie oben empfohlen) und der Fehler verschwindet. Was auch immer der Konflikt ist, er ist spezifisch für 4.2. Ich habe diese (oder nächste) Woche keine Zeit, einen Plunkr zusammenzustellen, aber es scheint sich um eine einzelne Aktion zu handeln, bei der zwei separate Observables im Store aktualisiert werden, von denen jede Auswirkungen auf die Benutzeroberfläche hat. Eines der UI-Updates findet statt, das andere verursacht die Ausnahme.

Hmmm,
Ein Rollback auf Version 4.1.3 löst das Problem definitiv und wendet auch ein Timeout an, wie von @jingglang gezeigt.

hi @tytskyi. Ich habe für dieses Problem einen Plunkr http://plnkr.co/edit/XAxNoV5UcEJOvsAbeLHT erstellt . hoffe es wird helfen.

Die von @jingglang angegebene
ODER auch das Ändern des emittierenden Ereignisses des Kindes in seinen Konstruktor löst den Fehler nicht mehr aus

@umens Sie aktualisieren die übergeordnete Komponente, nachdem sie überprüft wurde, und behalten daher den unidirektionalen Datenfluss nicht bei

@alexzuza wie kann ich das erreichen? Ich habe es immer so gemacht, ohne den Fehler. Warum das Setzen des SetTimout den Fehler nicht mehr auslöst. (Ich habe den Plunkr aktualisiert) Ich bezweifle, dass er den Lebenszyklus stört, oder?

hi @umens danke für deine zeit Das Problem ist, was @alexzuza sagt: Sie aktualisieren das übergeordnete Komponentenfeld, nachdem es überprüft wurde. Ihr Code entspricht in etwa dem folgenden Wert :
Warum hat es funktioniert? Wahrscheinlich aus Versehen hatte die alte Version von Angular oder Rxjs hier einen Fehler. Könnten Sie bitte sagen, welche Versionen verwendet wurden? Oder sogar in einen funktionierenden Plunker stecken?

Warum das Setzen des SetTimout den Fehler nicht mehr auslöst.

Weil Sie das Feld asynchron ändern, was den Einwegdatenfluss berücksichtigt.

Betrachten wir es aus dem Gegenteil: Warum wird ein Fehler ausgelöst? Die erste Überprüfung der Änderungserkennung erfolgt von oben nach unten. Es prüft den an die Vorlage gebundenen Wert von app.toolsConfig . Dann wird <child-cmp> gerendert, wodurch app.toolsConfig synchron aktualisiert werden. Das Rendern ist abgeschlossen. Jetzt wird die zweite Überprüfung (nur im Dev-Modus) der Änderungserkennung ausgeführt, um sicherzustellen, dass der Anwendungsstatus stabil ist. Aber app.toolsConfig vor dem Rendern des Kindes entspricht nicht app.toolsConfig danach. All dies geschieht während einer einzelnen "Umdrehung", "Zyklus" der Änderungserkennung.

in Ordnung. Vielen Dank für die ausführliche Antwort. Ich konnte keine Informationen darüber finden, wann der Lebenszyklus der untergeordneten Komponente eintritt.
für die vorherige "funktionierende" Version habe ich verwendet:
@ angle / *: 4.1.1 (außer compiler-cli -> 4.1.0)
rxjs: 5.3.1

@umens hier ist ein reproduzierter Fehler mit den alten Versionen, die Sie erwähnt haben: http://plnkr.co/edit/kfoKmigXzFXwOGb2wyT1?p=preview. Es wirft also wahrscheinlich eine Abhängigkeit von Drittanbietern das Verhalten oder eine nicht vollständige Reproduktionsanweisung?

kann nicht sagen.
Hier ist mein yarn.lock, wenn Sie daran interessiert sind, weiter zu gehen: https://pastebin.com/msARLta1
aber ich weiß nicht, was anders sein kann

Ich sehe ähnliche "ExpressionChanged ..." - Fehler nach dem Wechsel von 4.1.2 zu 4.2.3 .

In meinem Fall habe ich zwei Komponenten, die über einen Dienst interagieren. Der Service wird über mein Hauptmodul bereitgestellt und ComponentA wird vor ComponentB .

In 4.1.2 funktionierte die folgende Syntax ohne Fehler einwandfrei:

ComponentA-Vorlage:

<ul *ngIf="myService.showList">
...

ComponentB Klasse:

ngOnInit() {
  this.myService.showList = false; //starts as true in the service
  ...
}

In 4.2.3 muss ich die Vorlage von ComponentA wie folgt ändern, um den Fehler "ExpressionChanged ..." zu vermeiden:

ComponentA-Vorlage:

<ul [hidden]="!myService.showList">
...

Ich versuche immer noch herauszufinden, warum dies gerade erst zu einem Problem geworden ist und warum der Wechsel von *ngIf zu [hidden] funktioniert.

Ich habe das gleiche Problem und es passiert meistens, wenn ich eine asynchrone Pipe wie diese verwende:
<div>{{ (obs$ |async).someProperty }}</div>
Wenn ich es so benutze:

<div *ngIf="obs$ | async as o">
  <div>{{ o.someProperty }}</div>
</div>

Dann verschwindet der Fehler, und ich bin mir nicht sicher, ob es nur daran liegt, dass viele Leute einen Fehler gemacht haben, der vorher nicht erkannt wurde: Ich denke, in 4.2 wurde ein Fehler eingeführt…

Das gleiche Problem für mich. Das Problem scheint von @ angle / router zu kommen

Ich bin auch zu dem Schluss gekommen, dass es mit dem Router zusammenhängt. Ich habe gestern versucht, so viel zu posten, aber es sieht so aus, als wäre der Beitrag fehlgeschlagen. Ich habe weiter nachgeforscht und den Code vereinfacht, um festzustellen, ob ich den Fehler aufspüren kann. Der folgende Code funktioniert einwandfrei, wenn die ultimative Quelle der Aktion ein Klick auf eine Bedienfeldüberschrift ist, schlägt jedoch mit dem ExpressionChanged-Fehler fehl, wenn er über das Routing ausgelöst wird.

<span class="glyphicon pull-right" [ngClass]="{'glyphicon-chevron-up' : (ui$ | async)?.visiblePanels[VisiblePanel.IngredientTypes], 'glyphicon-chevron-down' : !((ui$ | async)?.visiblePanels[VisiblePanel.IngredientTypes])}"></span>

Dies hat mir geholfen, das Problem zu lösen! Sie müssen die Änderung im übergeordneten Element explizit auslösen.

Wie bei @acidghost könnte ich dieses Problem lösen, indem ich ChangeDetectorRef#detectChanges in AfterViewInit von meiner übergeordneten Komponente aus ausführen würde.

Wenn Sie plunkr repro haben, bin ich bereit, dies zu überprüfen, da wir einige ähnliche Beschwerden über Gitter hatten und es immer ein Benutzerproblem war.

Ich kann nicht sicher sein, ob ein Fehler in 4.2 eingeführt wurde oder ob der Fehler eher das Fehlen eines Fehlers in <4.2 war und in 4.2 behoben wurde.

Fehler: ExpressionChangedAfterItHasBeenCheckedError
Lösung:
componentRef.changeDetectorRef.detectChanges ();

Unten ist ein Teil aus meinem Code (dynamisch generierte Komponenten):
componentRef = viewContainerRef.createComponent (componentFactory); // Komponente wurde erstellt
(componentRef.instance) .data = input_data; // Komponentendaten hier manuell ändern
componentRef.changeDetectorRef.detectChanges (); // es wird zur Änderungserkennung führen

Für einfache Komponenten googeln Sie einfach, wie Sie auf "componentRef" zugreifen und dann ausführen
componentRef.changeDetectorRef.detectChanges ();
nach dem Einstellen / Ändern von Komponentendaten / Modell.

Lösung 2:
Beim Öffnen eines Dialogfelds "this.dialog.open (DialogComponent)" wurde dieser Fehler erneut angezeigt.
Das Einfügen dieses offenen Dialogcodes in eine Funktion und das anschließende Anwenden von setTimeout () auf diese Funktion löste das Problem.
Ex:
openDialog () {
let dialogRef = this.dialog.open (DialogComponent);
}}
ngOnInit (): void {
setTimeout (() => this.openDialog (), 0);
}}
obwohl es wie Hack scheint .. funktioniert !!!

Seit 4.2 habe ich das gleiche Problem und es hat keine Lösung oder Problemumgehung für mich funktioniert :( Ich erstelle eine Komponente dynamisch mit einer Komponentenfactory in einer ngAfterViewInit-Methode. Diese Komponente verwendet eine Direktive mit einem @Input() -Feld. Ich binde dies Feld zu einer statischen Zeichenfolge. Es scheint, dass das Feld @Input() der Direktive undefiniert ist, bis die Ansicht der Komponente erstellt und überprüft und erst dann mit der statischen Zeichenfolge initialisiert wurde.

https://plnkr.co/edit/E7wBQXm8CVnYypuUrPZd?p=info

staticComponent.ts

export class StaticComponent implements AfterViewInit {
  @ViewChild('dynamicContent', {read: ViewContainerRef})
  dynamicContent: ViewContainerRef;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  ngAfterViewInit(): void {
    const componentFactory: ComponentFactory<DynamicComponent> = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
    this.dynamicContent.createComponent(componentFactory);
  }
}

test.directive.ts

@Directive({
  selector: '[testDirective]'
})
export class TestDirective {
  @Input()
  testDirective: string;
}

dynamic.component.ts

@Component({
  selector: 'dynamic-component',
  template: `<div [testDirective]="'test'">XXX</div>`
})
export class DynamicComponent {
}

FEHLER Fehler: ExpressionChangedAfterItHasBeenCheckedError: Der Ausdruck wurde geändert, nachdem er überprüft wurde. Vorheriger Wert: 'undefiniert'. Aktueller Wert: 'Test'. Es scheint, dass die Ansicht erstellt wurde, nachdem die übergeordneten und untergeordneten Elemente überprüft wurden. Wurde es in einem Änderungserkennungs-Hook erstellt?

Ich bin etwas verwirrt, wenn ich diesen Thread lese. Ist dies ein bekannter Fehler, der in einer kommenden Version behoben wird? Oder ist das erwartetes Verhalten? Wenn ja, wie lautet die Lösung? Vielen Dank.

Keine Ahnung, ob es verwandt ist oder nicht, aber ich hasse diese Nachricht aus Leidenschaft! Dies wird NUR für mich angezeigt, wenn Unit-Tests mit dem sofort einsatzbereiten Befehl 'ng test' durchgeführt werden. Ich könnte nur verwirrt sein, wie man einen einfachen Dienst erfolgreich verspottet. Auch überrascht, dass noch niemand dies beim Testen gesehen hat, kann nichts Testbezogenes finden. Ich werde dieses Thema und jede Suche nach ExpressionChangedAfterItHasBeenCheckedError + Unit-Tests beobachten.

Ich habe versucht, ein plnkr zusammenzustellen, und es war sehr schwierig, den Fehler zu reproduzieren. Durch umfangreiches Debuggen bin ich jedoch meiner Meinung nach ein bisschen näher dran, zu sehen, was schief läuft (obwohl ich nicht entschieden habe, ob es sich um einen Fehler handelt). oder ein Fehler meinerseits).

Ich habe eine kleine Beispiel-App mit reduzierten Versionen derselben Reduzierungen erstellt, die in derselben Reihenfolge wie in der realen App kombiniert wurden, wobei der RouterReducer zuletzt verwendet wurde. Zu meiner Frustration trat der Fehler nicht auf. Also setzte ich Haltepunkte und beobachtete den Ablauf der Aktionen durch die Reduzierungen. Was ich fand, war, dass die beiden Apps Aktionen in umgekehrter Reihenfolge versendeten.

Mein UI-Reduzierer verwaltet die Sichtbarkeit und ist die Quelle der Statusänderung, die den Fehler auslöst. Hier ist eine abgespeckte Version des Reduzierers, die die relevanten Aktionen zeigt:


export const userInterfaceReducer = (state = INITIAL_UI(), action: any) => {
    switch (action.type) {
        case IngredientActions.LIST_INGREDIENTS:
            if (action.hideTypes) {
                return Object.assign(state, { visiblePanel: VisiblePanel.Ingredients });
            }
            return state;
        default:
            return state;
    }
}

Wenn ich dies in meiner kleinen Test-App ausführe, funktioniert es - zuerst wird die Aktion LIST_INGREDIENTS ausgelöst und der neue Status zurückgegeben. Dann wird die Aktion @ angle-redux / router :: UPDATE_LOCATION ausgelöst und der Standardfall wird getroffen, wobei derselbe Status zurückgegeben wird.

Wenn ich es in der eigentlichen App ausführe, werden die Reihenfolge oder Aktionen umgekehrt. Die Aktion @ angle-redux / router :: UPDATE_LOCATION wird zuerst ausgelöst und gibt den alten Status vom Standard zurück. Dann wird LIST_INGREDIENTS ausgelöst und der neue (geänderte) Status zurückgegeben - und der Fehler wird ausgelöst.

Ich bin völlig offen für die Idee, dass ich etwas Dummes getan habe und dies kein wirklicher Fehler ist - aber wenn ja, sieht jemand anderes, was ich getan habe?

(Als Fußnote habe ich die Version 4.1.3 überprüft ... und sie löst auch die Redux-Reduzierungen in der "richtigen" Reihenfolge aus - das heißt, die Standortänderung wird nach der Aktion "Liste der Inhaltsstoffe" ausgelöst, was vermutlich der Grund dafür ist, aber die 4.2-Version nicht).

Der gleiche nervige Fehler tritt auf, wenn eine Komponente die Eigenschaft des Dienstes ändert. Wird durch Verschieben von * ngIf in die übergeordnete Komponente behoben. Es ist also definitiv ein Fehler

konnte dies umgehen, indem die ngDoCheck () -Methode verwendet und die ChangeDetectorRef.detectChanges-Methode aufgerufen wurde.

public ngDoCheck(): void {
    this.cdr.detectChanges();
}

@pappacurds Mach das nicht. Sie haben damit unendliche Änderungserkennungszyklen verursacht.

Möglicherweise liegt hier derselbe Fehler vor: https://plnkr.co/edit/IeHrTX0qil17JK3P4GBb?p=preview

Fehler: previous undefined after undefiend

nach dem Update gleichen Fehler

Gleiche für mich

Alles in Ordnung in 4.0.0, nach dem Upgrade auf 4.2.6 erhalte ich den gleichen Fehler.

Der Artikel Alles, was Sie über den Fehler ExpressionChangedAfterItHasBeenCheckedError wissen müssen, erklärt ausführlich, warum dieser Fehler auftritt und mögliche Korrekturen

Korrekturen liegen auf der Hand, aber wenn das Framework so geändert wird, dass das Update dazu führt, dass Benutzeranwendungen neu geschrieben werden, um das neue kleinere Plattform-Update zu "unterstützen", ist dies verkabelt. JS behält immer noch alte Fehler bei, um die Kompatibilität aufrechtzuerhalten ...

Gleicher Fehler hier

Ich sehe dieses Problem auch in ~4.2.4 . Ein Downgrade auf ~4.1.3 das Problem behoben.

Das Problem besteht darin, Werte von ContentChildren zu ändern, selbst wenn ChangeDetectorRef detectChanges() am Ende von AfterViewInit des übergeordneten Elements (wo die Änderungen vorgenommen wurden) verwendet wird. Seltsamerweise tritt dieses Problem nur bei Komponenten und nicht bei Direktiven auf. Ich habe eine Direktive, mit der ich in 4.2.4 gearbeitet habe, in eine Komponente mit einer Vorlage von <ng-content></ng-content> konvertiert und dann den Fehler ExpressionChangedAfterItHasBeenCheckedError ausgelöst.

Ich habe dies während der Arbeit mit Material 2 Eingabesteuerung bekommen. Versucht, den Wert davon einzustellen

ngAfterViewInit(): void {
this.numberFormControl.setValue(200);
}

Ich habe einen einfachen Plunker zusammengestellt , der einen Fall zeigt, in dem die ExpressionChangedAfterItHasBeenCheckedError -Fehler erst ab Angular 4.2.x angezeigt wurden .

Ich habe einen einfachen Plunker erstellt , der den Fehler beim Ändern eines Werts von ContentChild anzeigt , selbst wenn ChangeDetectorRef detectChanges() in ngAfterViewInit der übergeordneten Komponente verwendet wird.

Bearbeiten: Erstellt auch einen einfachen Plunker basierend auf meinem ersten Beispiel, aber mit übergeordneter Direktive anstelle von Komponente und ohne Fehler.

@saverett Ich

@JSMike Ich hatte genau den gleichen Fall wie in Ihrem Plunker (habe ihn umgangen, ContentChild in setTimeout , Plunker verweist ,

@JSMike Danke für das Heads Up. Sieht aus wie ein Problem mit angle / zone.js # 832. Ich habe die zone.js-Version vorerst auf 0.8.12 gesetzt, bis die neueste zone.js behoben ist. Der Plunker sollte wieder funktionieren.

@matkokvesic das ist nicht wirklich eine Lösung, die nur bewirkt, dass die Änderung außerhalb des Lebenszyklus-Hooks erfolgt. Das bereitgestellte Codebeispiel verursacht bei Verwendung von Angular v4.1.3 keinen Fehler

@JSMike Ich stimme zu, es ist eine vorübergehende Problemumgehung. Die Verwendung von Elementen, auf die ContentChildren in ngAfterViewInit verweist, funktionierte vor Angular 4.2.6 einwandfrei.

Ich habe einen Plunker für den unter https://github.com/angular/angular/issues/17572#issuecomment -311589290 beschriebenen Fehler erstellt

https://plnkr.co/edit/E7wBQXm8CVnYypuUrPZd?p=info

Ich habe es behoben, indem ich changeDetection: ChangeDetectionStrategy.OnPush und this.changeDetector.markForCheck(); in meinem Code verwendet habe

@touqeershafi Wenn Sie this.changeDetector.markForCheck(); heißt das nicht, dass Sie die Dinge nicht richtig verwenden

Das passiert immer noch. Dies ist definitiv ein Fehler, kein erwartetes Verhalten und sollte behoben werden.

@istiti Ich verstehe, dass dies kein richtiger Weg ist, aber zumindest können Sie diesen Fehler vorübergehend TODO mit Fehler-URL hinzugefügt.

Das passiert immer noch. Dies ist definitiv ein Fehler, kein erwartetes Verhalten und sollte behoben werden.

Ich denke, ich muss @rwngallego zustimmen ... Vor dem 4.2.x-Update hatte ich bereits eine Reihe von wiederverwendbaren / ng-Content-Stlye-Komponenten geschrieben, die von @ViewChildren , @ContentChildren abhängen und dadurch Beziehungen zwischen Eltern und Kind herstellen Kanäle (Eigenschaften abrufen / einstellen usw.).

Ich muss ständig die ChangeDetectorRef-Instanz in all diese Konstruktoren einfügen (einschließlich untergeordneter Klassen, die diese Komponenten erweitern), und es fühlt sich nicht nach beabsichtigtem oder korrektem Verhalten an.

Für diejenigen, die dynamische Komponenten wie @saverett verwenden (die Verwendung von https://github.com/angular/angular/issues/15634.

Für alle, die Änderungen innerhalb von ngAfterViewInit / ngAfterViewChecked vornehmen, denke ich, dass dies erwartet wird.

Für die anderen (die ich hier noch nicht gesehen habe) ist es mir immer noch ein Rätsel.

Dies geschieht für mich im folgenden Szenario.
Haben Sie eine übergeordnete Komponente, die eine untergeordnete Komponente verwendet. Die untergeordnete Komponente benötigt Daten, die vom übergeordneten Element bereitgestellt werden. Diese Daten stammen jedoch aus einem Versprechungsergebnis im übergeordneten Konstruktor. Damit:

Elternteil

constructor {
dataservice.getData().then((result) => {
this.source = result;
});
}

Übergeordnete Vorlage

<app-child [source]="source"></app-child>

untergeordnete Komponente

@Input() source:any[];

Dieser Code löst diesen Fehler aus. Durch Hinzufügen dieses Fehlers zur übergeordneten Komponente wurde das Problem behoben:

constructor(private cdRef: ChangeDetectorRef) {
dataservice.getData().then((result) => {
this.source = result;
 this.cdRef.detectChanges();
});
    }

Ist dies nun eine empfohlene Lösung oder eine Problemumgehung für einen Fehler und welche Auswirkungen hätte eine solche Änderung? Für mich sieht es so aus, als würden Sie Angular anweisen, Änderungen zu erkennen, die Sie meiner Meinung nach vermeiden sollten ...

@sulhome ... Ihr Problem ist, dass das Versprechen im Konstruktor des Elternteils @Input für die untergeordnete Komponente ändert ... während des CD-Zyklus und dessen Bestätigung im Entwicklungsmodus. Das ist der Grund für den Fehler.

Die Zeile this.cdRef.detectChanges(); fügt den zweiten CD-Zyklus hinzu, sodass die Bestätigung nach dem Erfolg und => kein Fehler erfolgt.

Also funktioniert alles wie erwartet. Es ist wichtig zu verstehen, wie es funktioniert, die richtigen Konstrukte und die allgemeine Logik in Ihrem Code zu verwenden, um diese Art von Problemen zu vermeiden. Sie können darüber in der ausführlichen Erklärung hier lesen: https://hackernoon.com/jedes, was Sie wissen müssen, um den Ausdruck zu ändern, überprüft haben

@ mlc-mlapis Sie sagen also, dass ich es richtig mache, indem ich this.cdRef.detectChanges(); hinzufüge, und dass dies keine Auswirkungen hat?
Ich dachte, indem ich ngOnChanges auf das Kind höre, sollte ich die Änderung im @Input vom Elternteil ngOnChanges konzipiert

@sulhome Ja, this.cdRef.detectChanges(); hilft, aber es hat auch zur Folge, dass Sie jetzt 2 CDs haben. Es hängt also davon ab, wie und wo Sie die Strategie OnPush für Komponenten verwenden, um den Overhead von zu eliminieren noch ein CD-Zyklus.

Wenn es stimmt, dass dataservice.getData einige Daten über http verwendet, besteht die wahrscheinlich einfachste Lösung darin, ein Observable in diesem Dienst zu haben und es von der untergeordneten Komponente zu abonnieren. Wenn die Daten im Stream ausgegeben werden, kann das Kind darauf reagieren.

@ghetolay für den Datensatz, es gibt einige Fälle, in denen es sich um einen Fehler handelt, siehe zum Beispiel # 18129, den ich geöffnet habe.

Ich habe dieses Problem, wenn ich mit @Output Daten von einer untergeordneten Komponente erhalte.

bei der übergeordneten Komponente home.ts

drag_second(trigger){ console.log("dragged222222"+trigger); if(trigger){ this.isactive=true; }else{ this.isactive=false; } }
und home.html
<div class="upper" [ngClass]="{'isactive':isactive}">

isactive wird beim Dragstart und Dragend geändert ....

Fehlermeldung ist
ExpressionChangedAfterItHasBeenCheckedError: Der Ausdruck wurde geändert, nachdem er überprüft wurde. Vorheriger Wert: 'true'. Aktueller Wert: 'false'.

oder gibt es andere Möglichkeiten, wie ich Klassenattribute ändern / hinzufügen kann?

Gleiches Problem in 4.2.x und 4.3.0, jedoch nicht in 4.1.x.

Der Fehler tritt nur auf Routen auf, die ng-template .

Lösung: Das Einfügen des gesamten Codes in ngAfterViewInit in setTimeout das Problem für mich gelöst (danke / Dank an @jingglang).

public ngAfterViewInit(): void {
    setTimeout(() => {
        //my code
    });
}

@Wernerson , JSMikes Kommentar zu setTimeout. Es ist wichtig zu beachten, dass Sie den Code nur außerhalb des Lifecycle-Hooks ändern.

Mein Problem war, dass ich ActivatedRoute 's params Observable , um einen Status in ngOnInit() zu ändern. Es scheint, dass das Router das params synchron auslöst, sodass das Update während der CD erfolgt.
Meine einfache Lösung hierfür ist derzeit:

  // !!! see delay(0)
  // results are consumed by async Pipe, where I also had the CD issue (null vs. undefined)
  this.results = this._activatedRoute.params.delay(0)
    .do(params => this.searchParameters = this._createSearchParameters(params))
    .switchMap(p => {
      let key = this.searchParameters.key();
      return this._searchResultCache.results.map(r => r.get(key));
    });

(Ich weiß, dass dies nicht der schönste reaktive / funktionale Code aller Zeiten ist;))
So wurde die Lösung auf delay(0) der Parameter Emission durch einen tick .

Ich hoffe, ich kann anderen helfen, die ähnliche Probleme haben.
Auch Bedenken sind willkommen, wie falsch oder gefährlich meine Lösung ist.

Wie ist der Status dieses Problems? Es ist immer noch in Angular 4.2.6 ersichtlich.
Ist dies ein Problem bei Produktionsaufbauten? Da dieser Fehler nur bei Debug-Builds auftritt.

Ich hasse alle Problemumgehungen, wenn ich die Änderungserkennung manuell oder sogar in einem setTimeout () ausführe ...

setTimeout() ist ineffizient, da es einen neuen Änderungserkennungszyklus für die gesamte Anwendung verursacht, während detectChanges() nur die aktuelle Komponente AFAIK überprüft.

Mein Team hatte ein grundlegendes Missverständnis darüber, was ngOnInit ist und was nicht. Die Dokumente sagen

ngOnInit() : Initialisieren Sie die Direktive / Komponente, nachdem Angular zuerst die datengebundenen Eigenschaften angezeigt und die Eingabeeigenschaften der Direktive / Komponente festgelegt hat. Wird nach den ersten ngOnChanges () einmal aufgerufen.

Wir haben unsere Dienste (die den Anwendungsstatus verfolgen) ab ngOnInit abonniert. Unsere Abonnements sind synchrone BehaviorSubjects. Sie werden zur Abonnementzeit ausgelöst. "Nachdem Angular zuerst ... die Eingabeeigenschaften der Direktive / Komponente festgelegt hat", haben wir die Werte sofort geändert. Hier ist ein sehr einfacher Plunker, der zeigt, dass dies ein Problem ist.

Das Beispiel in Tour Of Heroes verwendet letztendlich http, das asynchron ist und daher keine Probleme verursacht. Ich denke, das ist die Quelle unserer Verwirrung.

Was wir jetzt tun, ist, stattdessen unsere synchronen Zustände von unserem Konstruktor zu abonnieren, damit die Werte unserer Komponenten sofort festgelegt werden. Andere in diesem Thread haben vorgeschlagen, eine zweite Änderungserkennung über Zeitüberschreitungen zu starten, Werte später festzulegen oder Angular explizit dazu aufzufordern. Dadurch wird verhindert, dass der Fehler auftritt, aber imho ist dies wahrscheinlich nicht erforderlich.

Der Artikel, den @maximusk geteilt hat, ist ein Muss : Alles, was Sie über den Fehler ExpressionChangedAfterItHasBeenCheckedError wissen müssen .

Wenn nichts anderes, sollte dieser Thread zu einer ausführlichen Warnung in den offiziellen eckigen Dokumenten führen.

Der Artikel, den @maximusk geteilt hat, ist ein Muss: Alles, was Sie über den ExpressionChangedAfterItHasBeenCheckedError-Fehler wissen müssen.

Vielen Dank

@adamdport

Funktioniert dies bei Verwendung von @ViewChildren @ContentChildren zum Ändern der untergeordneten Eigenschaften des Elements , da die untergeordneten Elemente erst verfügbar sind, nachdem der Lebenszyklus ngAfterViewInit () ausgeführt wurde?

Bitte beachten Sie, dass ein Teil dieses Problems ein bestätigter Fehler und kein Benutzerfehler ist:
https://github.com/angular/angular/issues/15634

Das angesprochene Problem @saverett ist korrekt. Die Verwendung von *ngIf den Fehler verursacht.

*Aufpassen...

Dies kann passieren, wenn Sie Objekte an ein Dialogfeld "Winkelmaterial" übergeben und sie dann im Dialogfeld direkt verwenden, anstatt this.myDataInput = Object.assign({}, dialogDataInput) . Dh this.myDataInput = dialogDataInput; und dann so etwas wie this.myDataInput.isDefault = !this.myDataInput.isDefault; . Wie oben erläutert, ändert die untergeordnete Komponente (Dialogfeld) Werte, die in der Ansicht der übergeordneten Komponente angezeigt werden.

Attribut durch [Attribut] ersetzen

Weiß jemand sicher, ob dies ein beabsichtigter Fehler oder ein Fehler ist?
Ist es nicht richtig, Daten in ngOnInit zu laden? Denn wenn ich den Code in den Konstruktor verschiebe (über ein Observable lade), wird der Fehler nicht ausgelöst ...

@Wernerson . Haben Sie * ngIf in Ihrem HTML? Beachten Sie, dass die Dinge gerendert werden, nachdem ngOnInit fertig ist. Solong, alles in * ngIf funktioniert nicht und kann zu diesem Fehler führen.

Es muss überarbeitet werden. Mit "ngIf" und benutzerdefinierten Steuerelementen erhalten Sie diese Fehlermeldung. Eine Auszeit ist sicherlich keine Lösung.

@ j-nord Wenn Sie die Kommentare lesen würden, würden Sie wissen, dass timeout nicht erforderlich ist.

@ j-nord / @dgroh Ich habe das gleiche erlebt. Ich habe einen ng-Hinweis verwendet, der eine ngIf-Direktive verwendet, und ich kann diesen Fehler nicht beseitigen. Haben Sie es geschafft, eine Problemumgehung zu implementieren?

@Wernerson Ja, ein Teil dieses Problems ist ein beabsichtigter Fehler oder ein Fehler: https://github.com/angular/angular/issues/15634

@ mawo87 es hat bei mir mit hidden funktioniert, da es das element nicht aus dem dOM entfernt. Für unsere Anforderung war dies in Ordnung und auch eine saubere Lösung.

@ mawo87
Zuerst müssen Sie die Variable finden, die mit der Fehlermeldung gemeint ist. @ Angular Team : Es wäre schön, den Namen der Variablen in der Fehlermeldung zu haben. Dies ist mit größeren Masken und Webpack nicht leicht zu finden. Wenn Sie den Befehl dort gefunden haben, wo er ausgeführt wird, hilft der Befehl in der folgenden Zeile:

this.cdr.detectionChanges();

Siehe das Beispiel von vermilion928 vom 19. Juni.

Danke @dgroh und @ j-nord.
@ j-nord Ich habe mir auch die DetectionChanges-Methode angesehen, aber ich könnte diesen Ansatz nicht verwenden, da im folgenden Artikel davon abgeraten wurde:
https://hackernoon.com/jedes - alles, was Sie wissen müssen, um den Ausdruck zu ändern, nachdem Sie den Fehlercode-Fehler-e3fd9ce7dbb4 überprüft haben

In meinem Fall verwende ich einen PageTitle-Dienst und abonniere ihn in der übergeordneten Komponente. Wenn untergeordnete Komponenten in die Ansicht geladen werden, legen sie den PageTitle im Dienst fest, und der übergeordnete Dienst erhält den Wert und zeigt ihn über das Abonnement an. Dies funktionierte in 4.1.x fehlerfrei, löst jedoch den ExpressionChangedAfterItHasBeenCheckedError-Fehler in 4.2x und höher aus.

Alles funktioniert immer noch wie erwartet und die Fehler werden in bereitgestellten / Produktions-Builds nicht angezeigt (aufgrund des Fehlens eines zweiten Änderungserkennungszyklus), aber in der Entwicklung befindet sich sehr viel Rot in meiner Konsole.

Ich bin mir immer noch sehr unklar, was die angemessene (auch kurzfristige) Lösung ist. Meine übergeordneten Komponentenabonnements befinden sich im Konstruktor, und die untergeordneten Komponentenaktualisierungen über den Dienst befinden sich in ngOnInit.

Ich habe den informativen Beitrag "Alles, was Sie wissen müssen ..." gelesen, der mich jedoch nicht zu der Annahme veranlasst, dass ich etwas falsch mache, und keine funktionierende Lösung für das Problem bietet.

@alignsoft Wenn Sie den Seitentitel in den untergeordneten Komponenten in ngOnInit festlegen würden, dann glaube ich, dass der Fehler gültig ist ... Siehe den Artikel, der zuvor verlinkt wurde.

@alignsoft Ich stimme zu, es wurde viel über diesen Fehler diskutiert, aber ohne wirklich klare Anweisung, ob er gültig ist oder nicht ... ist dies eher eine "Warnung" für den Entwickler bezüglich Standards und Datenbindung / -manipulation?

In meinem speziellen Fall habe ich es mit übergeordneten / untergeordneten Komponenten zu tun , die @ViewChild und @ContentChild verwenden , und aufrufen , um zu

@rolandoldengarm Ich habe versucht, den übergeordneten Konstruktor zu abonnieren und die Werte in AfterViewInit in den untergeordneten Komponenten festzulegen, und erhalte trotzdem den Fehler. Ist dies der richtige Weg, um dies basierend auf dem Ablauf- und Änderungserkennungszyklus zu handhaben, und der Fehler ist möglicherweise ein Fehler?

Bitte, es wäre toll, hier eine offizielle Antwort zu haben ...

Ich schaue mir das noch einmal an. Sieht aus wie mein Beispiel von https://github.com/angular/angular/issues/17572#issuecomment -315096085
sollte AfterContentInit anstelle von AfterViewInit wenn versucht wurde, ContentChildren als Teil des Komponentenlebenszyklus zu manipulieren.

Hier ist das aktualisierte plnkr mit AfterContentInit und ohne weitere Fehler: http://plnkr.co/edit/rkjTmqclHmqmpuwlD0Y9?p=preview

@JSMike Ich habe AfterViewInit in AfterContentInit geändert, immer noch der gleiche Fehler. Selbst wenn ich meine Daten innerhalb von OnInit aktualisiere, tritt der Fehler auf. Soweit ich weiß, ist dies gemäß dem Angular-Lebenszyklus korrekt (richtig?), Um Daten während OnInit zu initialisieren. Zusammen mit der Tatsache, dass dieser Fehler in früheren Versionen nicht aufgetreten ist, gehe ich davon aus, dass dies ein Fehler ist. Ich hätte jedoch gerne eine Erklärung vom Entwicklungsteam, wenn das so ist ..? : D.

@Wernerson Sie sollten keine Daten innerhalb von ngOnInit aktualisieren, es sei denn, die Daten sind an diesem Lebenszyklus-Hook verfügbar. Sie sollten Ihre Logik auf ngAfterContentInit wenn dies mit untergeordneten Inhalten zu tun hat.

@JSMike Hat nicht geholfen, der Fehler tritt immer noch auf. Ich abonniere gerade eine Statusänderung in der Anwendung, nachdem ich die angeforderten Daten (asynchron) in ngAfterContentInit .

@Wernerson hast du ein plnkr beispiel?

Grundmuster mit
Eine untergeordnete Komponente, die ein Ereignis ausgibt, und eine übergeordnete Komponente, die die lokale Variable aktualisiert.
Fehler in js console abrufen:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'hello world'.

Es wurde herausgefunden, dass ngAfterContentInit nur funktioniert, wenn die Kinder statisch sind. Es schlägt immer noch fehl, wenn Kinder mit *ngFor http://plnkr.co/edit/rkjTmqclHmqmpuwlD0Y9?p=preview erstellt werden

@soldiertt Sie brauchen nur detectChanges () https://stackblitz.com/edit/angular-qfu74y

@JSMike Wenn ich dies tue, wird ngAfterViewInit der untergeordneten Komponente nicht ausgelöst: https://stackblitz.com/edit/angular-bdwmgf

@soldiertt das scheint seltsam, sieht aber wie ein separates Problem aus, das gemeldet werden sollte.

@JSMike Mein Setup ist ziemlich komplex mit Diensten, Bibliotheken von Drittanbietern, vertraulichen Informationen usw. usw. Leider konnte ich den Fehler in einem Plunker nicht reproduzieren: /

Die Injektion von ChangeDetectorRef hat bei mir funktioniert!

Ich habe dieses Problem in einem Karussell, weil ich eine Eigenschaft für die Karussellelementkomponente festlegen muss, eine Eigenschaft, die erst bekannt ist, nachdem sie in der übergeordneten Karussellkomponente berechnet wurde. Und alle Elemente kommen durch ng-content , sodass ich nur mit den Elementen in ngAfterContentInit der übergeordneten Karussellkomponente arbeiten kann. Etwas wie:
Karussell:

@ContentChildren(ItemComponent) carouselItems;

ngAfterContentInit() {
  // ... some computations
  this.carouselItems.forEach((item: ItemComponent, currentIndex) => {
    item.setPropertyX(someComputedValue);
    // OR:
    item.x = someComputedValue; // of course, this would work as well
  });
}

Artikel:

setPropertyX(value) {
  this.x = value;
}

Wäre neben dem setTimeout() -Hack die einzige andere Lösung, einen Dienst und ein Subjekt zu verwenden, damit die Elemente mit dem übergeordneten Karussell kommunizieren? Ich meine, das wäre lächerlich ... Das würde bedeuten, wenn ich 100 Artikel in einem Karussell hätte, hätte ich 100 Abonnements. Und das verdoppelt sich, wenn ich 2 Karussells habe. Das kann doch nicht der empfohlene Weg sein?! Recht?

Meistens müssten wir einige Eigenschaften für unsere Komponenten festlegen, Eigenschaften, die nicht vor AfterContentInit ... Und in vielen Fällen (wenn wir nicht über 1 oder 2 Komponenten wie sprechen das, aber eher 50 oder 100 wie in einem Karussell) mit Zehnteln oder Hunderten von Abonnements wäre lächerlich.

Gibt es einen wirklich coolen Teil von Angular, der mir hier helfen kann, den ich noch nicht entdeckt habe?

PS Ich habe auch versucht, ChangeDetectorRef zu injizieren und detach() sowohl für die Karussellkomponente als auch für die Artikelkomponente zu verwenden. Ich hätte erwartet, dass dies den Fehler behebt, da ... ich sage im Grunde "_Schraubenwechselerkennung, ich brauche sie eigentlich gar nicht. Bitte, bitte schön: Erkenne KEINE Änderungen _" ... aber der fehler wird immer noch geworfen! Also, was bringt die detach() -Methode, wenn sie nicht das tut, was sie sagt?

constructor(private cdr: ChangeDetectorRef) {
  this.cdr.detach();
}

setTimeout() ist kein Hack erforderlich. ngAfterViewInit .

Das Problem ist, wenn Sie es als Magie verwenden, ohne wirklich zu wissen warum. Es gibt jedoch völlig gültige Szenarien, in denen die Verwendung von setTimeout() der richtige Weg ist.

@ghetolay Ist es nicht schwierig, aus dem Lebenszyklus der Komponente (n) auszubrechen, die das Änderungserkennungssystem ausweicht? Ich habe die Route ChangeDetectorRef.detectChanges () eingeschlagen, aber das fühlt sich für mich sogar wie ein Hack an ... Wenn eine dieser Lösungen "akzeptabel" ist, müssen wir wahrscheinlich damit leben, aber es bricht wirklich jede Verwendung der Modifikation ViewChild (ren) oder ContentChild (ren)

@ Fugwenna

Ist es nicht schwierig, aus dem Lebenszyklus der Komponente (n) auszubrechen, die das Änderungserkennungssystem ausweicht?

Ich verstehe diese Frage nicht. aus dem Lebenszyklus ausbrechen?

Angular führt jedes Mal eine CD-Runde aus, wenn ein asynchrones Ereignis auftritt (dom-Ereignis, xhr, setTimeout usw.). Während dieser CD wird die Ansicht aktualisiert. ngAfterViewInit hook wird danach ausgeführt, sodass keine CD mehr zum Ausführen geplant ist und erst wieder ausgelöst wird, wenn ein anderes asynchrones Ereignis auftritt. Die Verwendung von setTimeout() ist der einfachste Weg, um es erneut auszulösen. Sie könnten es sicherlich selbst tun, aber ich denke, die Vorteile sind vernachlässigbar.

@ghetolay Ich @JSMike und einige andere

@matkokvesic das ist nicht wirklich eine Lösung, die nur bewirkt, dass die Änderung außerhalb des Lebenszyklus-Hooks erfolgt. Das bereitgestellte Codebeispiel verursacht bei Verwendung von Angular v4.1.3 keinen Fehler

Ich denke also, dass die Verwendung von setTimeout () dazu führt, dass der Lebenszyklus-Hook "übersprungen" oder nicht wie gewohnt ausgewertet wird?

@ghetolay @fugwenna was ist mit der detach() -Methode der ChangeDetectorRef ? Irgendwelche Gedanken? Sollte dies die Änderungserkennung nicht vollständig deaktivieren und somit auch den Fehler beseitigen? Ich verstehe nicht, warum es nicht funktioniert? Oder wird der Fehler "unabhängig" davon geworfen? Bedeutet das, dass Angular sich nicht wirklich darum kümmert, dass wir die Änderungserkennung deaktiviert haben, sondern nur darum, dass wir eine Eigenschaft geändert haben, nachdem sie festgelegt wurde?
Wenn die Leute immer noch darüber streiten, dass "ExpressionChangedAfterItHasBeenChecked" ein Fehler ist oder nicht, ist dies definitiv ein Fehler ... Meiner Meinung nach sollte Angular sich nicht mehr darum kümmern, dass wir die Eigenschaften ändern, nachdem sie vollständig festgelegt wurden, wenn wir sie vollständig festgelegt haben Änderungserkennung deaktiviert. Besonders so, wie ich es gemacht habe, für die übergeordnete Komponente und alle anderen untergeordneten Komponenten, im Grunde genommen für einen ganzen Baum.

Ich bin hier ein bisschen verloren. Eines der Probleme, das ich habe, ist, dass ich nicht sicher bin, wie ich überhaupt einige sehr häufige Dinge tun würde, ohne die Ausnahme im Dev-Modus auszulösen.

Zum Beispiel habe ich eine Accessor-Komponente für Steuerwerte geschrieben, die einen Datepicker kapselt. Ich füttere diese Komponente mit einem leeren Modell, das intern an den Datepicker übergeben wird, der es initialisiert und über die registrierte Funktion zurücksendet. Natürlich modifizieren die Kinder das Modell während der Initialisierung, aber genau das möchte ich! Ich möchte ein initialisiertes Modell zurückerhalten, aber die Initialisierung nicht im übergeordneten Modell durchführen, da es der Datepicker ist, der die Vorgehensweise übernimmt.

Die Frage ist, wie würde ich das jetzt tun? SetTimeout aufrufen und Änderungserkennung erneut auslösen? ChangeDetectorRef verwenden? Ich mag es nicht, weil es den Code wirklich schwer lesbar macht. Sache in einem separaten Dienst initialisieren? Dieser Service dient jedoch nur einem sehr technischen Zweck ohne geschäftlichen Wert, und ich bin mir nicht einmal sicher, ob dies das Problem lösen wird.

@fugwenna Mein Hauptanliegen war, dass es in 4.1.3 funktioniert hat und jetzt kaputt ist. Ich habe noch niemanden im eckigen Team gesehen, der angibt, ob wir setTimeout in unseren Init-Funktionen verwenden und Zonen übernehmen sollen, aber es fühlt sich im Vergleich zu früher wie ein Anti-Pattern an.

@ kavi87 Diese Stackoverflow- Frage gab mir also tatsächlich die elegante Lösung, die ich brauchte. Welches sollte den Ereignisemitter in meiner untergeordneten Komponente
new EventEmitter(true)

Für ein Problem, das als Regression mit 109 Kommentaren gekennzeichnet ist, ist dieses Problem mit jedem offiziellen Wort enttäuschend leise.

Während alle hier gute Arbeit mit den Selbsthilfetechniken leisten, würde ich gerne wissen, ob dies tatsächlich ein Fehler ist oder nur ein neues Verhalten, das ab 4.2.x implementiert wurde. Wenn ja, sollte es als bahnbrechende Änderung aufgeführt sein (und somit nicht als geringfügige Veröffentlichung?)

@ MrCroft
Ich bin mir nicht sicher, ob das Deaktivieren der Änderungserkennung, um eine Ausnahme zum Schweigen zu bringen, ein guter Weg ist, obwohl ich theoretisch sehe, wie es sinnvoll sein sollte / könnte.

Ich stimme @JSMike und @rosslavery in Bezug auf sehr wenige Antworten oder Erklärungen zu, warum diese Fehlermeldung nach 4.2x ohne Dokumentation von Änderungen aufgetreten ist. Ein weiteres rätselhaftes Stück davon ist jedoch, wie sie anscheinend nur hineingeworfen wird Entwicklungsmodus, der sich fast eher wie eine Warnung vor einer Unterbrechung der Änderungserkennung anfühlt (?)

Im meine AppComponent habe ich eine div.
Der einzige Zweck für dieses Div besteht darin, eine ausgelastete Überlagerung anzuzeigen.
Der Besetztzustand wird innerhalb einer http-Serviceklasse ausgelöst:

app.component.html

<!-- Busy Overlay -->
<div *ngIf="busy$ | async"
     class="overlay">
    <i class="loading">
        <i><sk-wave></sk-wave></i>
    </i>
</div>

app.component.ts:

  get busy$(): Observable<boolean> {
    return this.catolService.busy$;
  }

Nach dem Upgrade auf 4.3.4 erhalte ich immer einen ExpressionChangedAfterItHasBeenCheckedError, wenn der Dienst den Besetztzustand auslöst.

Gibt es eine Lösung für dieses einfache asynchrone Szenario?

@ Mukunku Danke, das werde ich versuchen.

@ mlc-mlapis Ich habe Ihren Plunker leicht geändert. Mein Code lautet genau https://plnkr.co/edit/uUT7tiM5BKPIy2upJPhb?p=preview

aber der Plunker zeigt das Problem nicht. Ich werde versuchen, auf die neueste Version 4.x zu aktualisieren, um festzustellen, ob das Problem behoben wurde.

Vielen Dank

Hallo zusammen - Entschuldigung für die Verzögerung hier.

Also - dieses Verhalten funktioniert tatsächlich wie beabsichtigt, was für einige Leute möglicherweise unerwartet ist. Lassen Sie mich also versuchen, die Mechanik zu erklären.

Der Plunker von @saveretts ist ein guter Repro davon (danke!) - https://plnkr.co/edit/fr7rTNTCgEhHcbKnxAWN?p=preview

Das tldr ist, dass Angular immer so funktioniert hat - die Änderungserkennung wird von oben nach unten (oder übergeordnet -> untergeordnet) in einem einzigen Durchgang ausgeführt. Also, wenn wir haben:


@Component({ 
  selector: 'app-root',
  template: `
    <!-- initially falsey -->
    <div *ngIf="sharedService.someValue">NgIf Block</div>
    <child-comp></child-comp>
  `
})
class AppRoot {
  constructor(public sharedService:SharedService){}
}
@Component({ 
  selector: 'child-component',
  template: `child comp`
})
class ChildComponent {
  constructor(public sharedService:SharedService){}
  ngOnInit(){
    this.sharedService.someValue = true;
  }
}

Die Änderungserkennung wird zuerst für das App-Stammverzeichnis ausgeführt, überprüft alle Bindungen und ändert dann die untergeordnete Komponente - erneut, da wir dies in einem einzigen Durchgang tun (und nicht im AngularJS-Stil, bis es stabil ist), der übergeordneten Bindung (in diesem Fall * ngIf) wird nicht erneut überprüft. Ihre Anwendung befindet sich jetzt in einem inkonsistenten Zustand (!).

Im Entwicklungsmodus führen wir diese Änderungserkennung tatsächlich zweimal aus. Beim zweiten Ausführen wird überprüft, ob sich die Bindungen nicht geändert haben (was auf einen inkonsistenten Status hinweisen würde), und der Fehler wird ausgelöst, wenn ein solches Problem gefunden wird. Sie können dieses Verhalten überprüfen, indem Sie im Repro enableProdMode() aufrufen: https://plnkr.co/edit/GGEzdxK1eHzHyGiAdp56?p=preview. Beachten Sie, dass der Fehler nicht ausgelöst wird (weil wir keine CD x2 ausführen), die Anwendung jedoch in einem inkonsistenten Zustand endet (das untergeordnete Element wird angezeigt, aber nicht das * ngIf), was eine schlechte Sache ist.

Der Grund, warum dies kürzlich aufgetaucht ist, ist, dass der Router zuvor beim Einfügen von Komponenten eine Reihe zusätzlicher Änderungserkennungsprüfungen durchgeführt hat. Dies war ineffizient und verursachte Probleme mit Animationen und Routing, insbesondere wenn Router-Outlets in ngIfs und dergleichen verschachtelt sind Dieses Verhalten wurde behoben, was dazu führte, dass bereits falscher Code wie oben * jetzt korrekt einen Fehler auslöste, dass der Entwickler den Einweg-Datenfluss verletzt.

Ich würde argumentieren, dass normalerweise Code, der diesen Einwegfluss verletzt (wie der obige Repro), falsch ist . Es gibt jedoch Fälle, in denen Sie dieses Verhalten möglicherweise wünschen (tatsächlich haben wir ein ähnliches Setup in der Angular Forms-Bibliothek). Dies bedeutet, dass Sie explizit einen weiteren Änderungserkennungslauf auslösen müssen (der zur Stammkomponente zurückkehren und von oben nach unten überprüfen würde). Wenn Sie setTimeout aufrufen, wird dies erreicht. In der Regel ist es jedoch besser, ein Versprechen zu verwenden, um dies auszulösen - siehe https://plnkr.co/edit/IoKMxEOlY9lY9LcWwFKv?p=preview

Hoffentlich hilft das!

@robwormald Dieser Fehler trat auch bei anderen Szenarien auf. Ich bin nicht sicher, ob dies das Problem mit ContentChildren behebt . Warum kann eine Direktive die Werte von Kindern während AfterContentInit ohne Fehler ändern, aber dasselbe in einer Komponente zu tun, wirft Fehler aus?

Wird auch erwartet, dass die anderen Init-Funktionen nicht aufgerufen werden, wenn während eines Init-Prozesses ein cdr.detectChanges() aufgerufen wird? Dies ist etwas, das in diesem Thread entdeckt wurde , für das ich ein separates Problem erstellt habe .

@robwormald

Ich glaube, @JSMike ist richtig in der Einschätzung, dass dieser Fehler immer noch in Szenarien ausgelöst wird, in denen der Einwegfluss von einem übergeordneten> untergeordneten Element mit ContentChild (ren) und ViewChild (ren) kommt.

Ist es akzeptabel zu berücksichtigen, was ich zuvor gesagt habe , dass dieser Fehler eher eine "Warnung" ist, die besagt, dass der Entwickler gegen die "Best Practice" des Einwegflusses verstößt, aber seit der Änderungserkennung keine Anwendungsfehler verursacht läuft nur einmal im Produktionsmodus (reale Welt)?

@fugwenna Nein, dies ist wirklich ein Fehler, da sonst die Ansicht in einem inkonsistenten Zustand bleibt. Das Beispiel, das Rob durchläuft, erzählt alles.

Es gibt auch dieses Zitat aus den Dokumenten

Die unidirektionale Datenflussregel von Angular verbietet Aktualisierungen der Ansicht, nachdem sie erstellt wurde. Beide Hooks werden ausgelöst, nachdem die Ansicht der Komponente erstellt wurde.

Wenn Sie dort wirklich etwas ändern müssen, verwenden Sie dazu eine der asynchronen Methoden. setTimeout könnte hier geeignet sein, aber beachten Sie, dass dies mit einer (zum Zeitpunkt dieses Schreibens) eigenen Verzögerung von 4 ms einhergeht. Ein anderer Weg ist Promise.resolve().then(() => Assignment = here)

Noch besser ist es, einen Schritt zurückzutreten und herauszufinden, warum Sie so spät im Prozess eine Änderung vornehmen müssen, und zu prüfen, ob es einen saubereren Weg gibt, um das Problem zu lösen. Wenn ich dies tue, behandle ich es als Codegeruch.

Vielen Dank für die ausführliche Erklärung @robwormald. Ich bin immer noch verwirrt, warum ein untergeordneter -> übergeordneter Datenfluss immer noch zu funktionieren scheint, wenn eine [hidden] -Bindung anstelle von *ngIf (siehe https://plnkr.co/edit/L4QWK5pTgF1qZatFAN4u?p = Vorschau). Irgendwelche Ideen, warum dies immer noch funktioniert, ohne ein ExpressionChangedAfterItHasBeenCheckedError ?

Angular verwendet die Funktion

Eine kurze Darstellung dieser Funktion könnte folgendermaßen aussehen:

function checkAndUpdateView(view) {
    // update bound properties and run ngOnChanges/ngOnInit/ngDoCheck for child directives
    updateDirectives
    // check all embedded views that belong current view
    execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
    // update DOM for the current view
    updateRenderer
    // perform checkAndUpdate for all child components
    execComponentViewsAction(view, ViewAction.CheckAndUpdate);
}

Es wird rekursiv dank der Methoden execEmbeddedViewsAction und execComponentViewsAction . Ein weiterer wichtiger Punkt ist die Winkelprüfung eingebetteter Ansichten, nachdem Anweisungen überprüft wurden und bevor DOM aktualisiert wird.

Um das @ saverett- Beispiel zu vereinfachen,

<div *ngIf="!sharedService.displayList">Some text</div>
<router-outlet></router-outlet>

https://plnkr.co/edit/OdkzHjEXbEd3efYAisFM?p=preview

Wir haben bereits gewusst, dass *ngIf nur Desugar ist. Damit

<ng-template [ngIf]="sharedService.displayList">
  <div>Some text</div>
</ng-template>
<router-outlet></router-outlet>

Wir können uns folgende Struktur vorstellen:

  my-app
     |
   NgIf directive
       NgIf EmbeddedView
   RouterOutlet directive

Was macht die Direktive RouterOutlet ?

Es fügt geroutete Komponenten in ViewContainerRef ein

activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
    ...
    this.activated = this.location.createComponent(factory, this.location.length, injector);

Dies bedeutet, dass router-outlet EmbeddedView Nachdem die Direktive RouterOutlet initialisiert wurde, haben wir zwei eingebettete Ansichten in unserer Ansicht AppComponent .

  my-app
     |
   NgIf directive ([ngIf]="sharedService.displayList")
       NgIf EmbeddedView
   RouterOutlet directive 
      BComponent EmbeddedView

Lassen Sie es uns auf dem Bild veranschaulichen

haschanged

Kommen wir nun zu unserer Hauptfunktion zurück

function checkAndUpdateView(view) {
    // update bound properties and run ngOnChanges/ngOnInit/ngDoCheck for child directives
    updateDirectives
    // check all embedded views that belong current view
    execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
    ...
    // update DOM for the current view
    updateRenderer
    ...
}

Angular führt die Prüfung in der folgenden Reihenfolge durch:

NgIf directive ([ngIf]="sharedService.displayList") updateDirectives(1)
      NgIf EmbeddedView   execEmbeddedViewsAction(2)
RouterOutlet directive 
      BComponent EmbeddedView  execEmbeddedViewsAction(3)

Unsere NgIf Direktive wird zuerst überprüft (hier wird an sharedService.displayList=false erinnert) und dann wird die Methode NgOnInit innerhalb von BComponent aufgerufen (wo wir sharedService.displayList ändern) true ) Und wenn Angular checkNoChanges ausführt, wird der Fehler Expression has changed after it was checked

Dann ersetzen wir *ngIf durch [hidden] . Jetzt wird nur noch eine eingebettete Ansicht von RouterOutlet eingefügt, und unsere [hidden]="sharedService.displayList" werden innerhalb von updateRenderer überprüft

  my-app
     |
   div{Some Text} just a node
   RouterOutlet directive 
      BComponent EmbeddedView

Angular führt eine Überprüfung wie folgt durch:

function checkAndUpdateView(view) {
    // check all embedded views that belong current view
    execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);   BComponent.ngOnInit (1)
    ...
    // update DOM for the current view
    updateRenderer   update hidden binding (2)
    ...
}

Auf diese Weise verursacht die Bindung von dom-Eigenschaften den Fehler nicht, da wir nach dem Aufruf von ngOnInit value aktualisiert haben.

Das ist der Hauptunterschied zwischen der Strukturrichtlinie *ngIf und der Dom-Eigenschaftsbindung [hidden]

Vielen Dank für die detaillierte Übersicht @alexzuza! Es war sehr hilfreich!

setTimeout () hat tatsächlich für mich funktioniert :) Danke @jingglang :)
.subscribe (data => setTimeout (() => this.requesting = data, 0))

@robwormald ist hier richtig. Ich hatte das gleiche Problem und es war schwieriger zu erkennen, weil ich NGRX und Observables verwendete. Das Problem, das ich hatte, war, dass es Komponentencontainer auf verschiedenen Ebenen in der Routenhierarchie gab, die den Speicherstatus abonnierten. Sobald ich meine Containerkomponenten in meinem Funktionsmodul auf die gleiche Ebene verschoben habe, ist das Problem behoben. Ich weiß, dass dies eine Art verschlungene Antwort ist, aber wenn Sie zufällig ein NGRX-Container- / Komponentenmuster verwenden, weist dies Ihre Untersuchung hoffentlich in die richtige Richtung

Mit setTimeOut funktioniert es, danke @jingglang
ngAfterViewInit () {
this.innerHeight = (window.innerHeight);
setTimeout (() => this.printPosition (), 0);
}}

@alexzuza , das passiert nicht nur für ngIf, das passiert (zumindest für mich) auch mit [ngClass]

@ Ninja-Coding-Git Ich habe gerade einen speziellen Fall beschrieben. Ich weiß, dass es mit jedem Code passieren kann.

Für mich löste das Aufrufen von ChangeDetectorRef nach dem Ändern des Elements das Problem:

import { Component, ChangeDetectorRef } from '@angular/core'

@Component({
  selector: 'my-app',
  template: `<div>I'm {{message}} </div>`,
})
export class App {
  message: string = 'loading :(';

  constructor(private _cdr: ChangeDetectorRef) {}

  ngAfterViewInit() {
    this.message = 'all done loading :)'
    this._cdr.detectChanges();
  }

}

Lösung hier gefunden

hallo @thetylerb! Könnten Sie das näher erläutern? Wir verwenden ngrx und ich weiß einfach nicht, wie ich das kompensieren soll. Ich denke, es ist ziemlich umständlich, Versprechen zusätzlich zu Observablen zu verwenden.

@ piq9117 Sie können auch einen Blick auf diesen Kommentar werfen https://github.com/angular/angular/issues/18129#issuecomment -326801192 Ich habe die Interaktion zwischen Änderungserkennung und ngrx gemacht, es kann hilfreich sein, nehme ich an

@ Victorornoel danke! Das beschreibt ziemlich genau unsere Situation. Wir haben verschachtelte unveränderliche Datenstrukturen (unveränderliche js) und verwenden überall asynchrone Pipes. Meine ersten Gedanken waren, dass der Speicher den Komponentenbaum ändern würde, wenn der Speicher hydratisiert wurde, und der Komponentenbaum diese Änderung nur kompensieren und eine weitere Änderung vornehmen würdeDetection 😓

Wir haben verschachtelte unveränderliche Datenstrukturen (unveränderliche js) und verwenden überall asynchrone Pipes. Meine ersten Gedanken waren, dass der Speicher den Komponentenbaum ändern würde, wenn der Speicher hydratisiert wurde, und der Komponentenbaum diese Änderung nur kompensieren und eine weitere Änderungserkennung durchführen würde.

In meinem Projekt haben wir eine Art normalisierte Datenstruktur (anstelle von verschachtelten Datenstrukturen), so dass diese Art von Problemen ein wenig gemildert wird, bis dies nicht mehr der Fall ist! :Ö

Sie hoffen nur, dass entweder:

  • Wenn Sie Datenstrukturen so ändern, dass Änderungen an einem Teil keine Aktualisierungen für andere Teile auslösen
  • Achten Sie darauf, keine Ereignisse von untergeordneten Komponenten von Komponenten auszulösen, die den Speicher über eine asynchrone Pipe abhören
  • Auslösen der manuellen Änderungserkennung, wenn Sie die oben genannten Ereignisse auslösen
  • Lösen Sie dieses Ereignis zu einem anderen Zeitpunkt oder in einem setTimeout aus

Ich benutze ngrx und habe folgende Situation:

In app.component.html:
<div *ngIf='(appState | async).show'>test</div>
Und in app.component.ts
this.appState= this.store.select("app");

Natürlich bekomme ich in dieser Situation den Fehler, aber wenn ich ein boolesches Flag in eine Komponente wie diese einfüge:
app.component.html -> <div *ngIf='show'>test</div>
app.component.ts ->
this.appState.subscribe((state: AppState) => { this.show= state.show; })

Der Fehler ist weg, natürlich ist es für mich verständlich warum, aber ich möchte Ihre Meinung wissen, ist es eine gute Lösung? Was sind Vor- und Nachteile?

Ich benutze ngrx nicht, habe aber das Problem mit einer einfachen Überprüfung mit querySelectorAll let chips = [].map.call(document.querySelectorAll('li.chip'), this.chipVisible);

Die Lösung von @bogdancar mit ChangeDetectorRef.detectChanges() unterdrückt den Fehler, aber es wäre schön, ChangeDetectorRef nicht importieren zu müssen, indem behoben wird, was den Fehler überhaupt verursacht.

Ich habe das gleiche Problem, wenn ich rxjs in Winkel 4.4.4 verwende. Ich abonniere nur ein beobachtbares Objekt, das vom DI-Dienst bereitgestellt wird. Meine Arbeit unten:

this.eventBroadcastService.getCustomEvent({type: 'loginOpen'}).subscribe(e => { setTimeout(() => { this.isBlur = true; }, 0); });

Ich benutze ein setTimeout, um das Problem zu umgehen. Jetzt funktioniert es, aber es ist schwierig. Ich fühle mich nicht gut.

ngOnChanges (Änderungen: SimpleChanges | any) macht den Trick

Das Problem wurde einfach behoben, nachdem die Logik der sich dynamisch ändernden Parameter innerhalb der ngDoCheck () -Methode verschoben wurde.
ngDoCheck(): void { this.checkValid = this.sourceArr.includes((this.chanedVal).toUpperCase()); }

@ asrinivas61 Ich denke, das ist eine wirklich schlechte Idee. ngDoCheck wird von Angular häufig aufgerufen, und wenn Ihr sourceArr viele Daten enthält, kann dies Ihre Leistung beeinträchtigen.

Siehe https://angular.io/guide/lifecycle-hooks#other -angular-lifecycle-hooks

Ich würde vorerst eher empfehlen, ngAfterViewInit mit setTimeout :

setTimeout(_ => /* your code here */, 1000);

Beispiel:

  public ngAfterViewInit(): void {
    // We use setTimeout to avoid the `ExpressionChangedAfterItHasBeenCheckedError`
    // See: https://github.com/angular/angular/issues/6005
    setTimeout(_ => this.isLoadingInProgress = false, 1000);
  }

@dgroh Sie müssen kein tatsächliches Timeout hinzufügen. Sie möchten nur, dass js Ihren Code in einer nächsten asynchronen Task ausführt, was einen weiteren Änderungserkennungslauf bedeutet.

@victornoel Ich glaube kaum, dass dies mit Observablen funktionieren würde, wenn Sie nicht ausdrücklich detectChanges von ChangeDetectorRef aufrufen. Ich wünschte, das alles wäre nicht nötig.

@dgroh du musst mich missverstanden haben, ich habe mich nur für das Schreiben

public ngAfterViewInit(): void {
    // We use setTimeout to avoid the `ExpressionChangedAfterItHasBeenCheckedError`
    // See: https://github.com/angular/angular/issues/6005
    setTimeout(_ => this.isLoadingInProgress = false);
  }

Ist es nicht möglich, einen Schritt nach ngAfterViewInit wie einen setTimeout hinzuzufügen? (zum Beispiel: ngAfterViewLoad )

@ aks4it , das scheint zu funktionieren, aber ich würde gerne mehr Details darüber

Die offizielle Plunker-Demo von Docs weist denselben Fehler auf. Könnten Sie es dort beheben? :) Vielen Dank

@luckylooke

  ngAfterViewInit() {
    //this.loadComponent();
    this.getAds();
  }

das funktioniert?

Ich verstehe Ihre Anforderung nicht, aber Sie möchten wirklich ein Intervall von 3 Sekunden? Wenn ja, funktioniert dies, und selbst wenn Sie loadComponent direkt aufrufen möchten, ist mir Folgendes gelungen:

ngAfterViewInit() {
    setTimeout(()=>{this.loadComponent()},0)
  }

@istiti Ich konnte es durch ChangeDetectorRef Workaround beheben und detectChanges() nach ... data = data setzen

Aber da es sich um offizielle Dokumente handelt, war ich neugierig auf die offizielle Lösung des Problems. Kein Timeout oder ChangeDetectorRef.

Es tut mir leid, dass ich im ersten Beitrag zu kurz war. Ich wollte auf die Schwere des Problems hinweisen, da selbst die eckigen Dokumente den gleichen Code haben.

Nur zu Ihrer Information, ich bin mir nicht sicher, was hier wirklich verursacht, aber Fehler sind verschwunden, wenn ich den Prod-Modus in main.ts aktiviert habe
`enableProdMode ()

// if (environment.production) {

// enableProdMode ();

//} `

"@ angle / core": "^ 4.2.4"
"Typoskript": "~ 2.3.3"

@bakthaa ... es wird angenommen, dass das Verhalten, weil die Kontrollprüfung (ob die Werte der Komponenten @Inputs() gleich sind), die nach jedem CD-Zyklus aufgerufen wird, nur im Entwicklungsmodus und nicht im Produktionsmodus der Angular-App aufgerufen wird. Das Problem ist also im Produktionsmodus verborgen, aber es ist immer noch vorhanden ... und kann wahrscheinlich eine Quelle für verschiedene unerwünschte oder irreführende Nebenwirkungen im Produktionsmodus sein.

Ich verwende Angular 5 und konnte dieses Problem beheben, indem ich das ChangeDetectorRef in die Komponente injizierte und es zwang, Änderungen zu erkennen.

    constructor(private changeDetector: ChangeDetectorRef) {}

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

@ Sabri-Bouchlema ... ja, es ist eine Möglichkeit ... aber trotzdem sollten Sie noch einmal überlegen ... warum eine Komponente @Inputs während eines CD-Zyklus geändert wird ... und entscheiden, ob die Logik ist richtig ... und es ist wahr, dass in 95% der Fälle der Code geändert werden kann, um das Problem zu vermeiden, ohne zusätzliche detectChanges() aufzurufen.

Verwenden von Winkel 5.1.2. Ich erhalte diesen Fehler beim Öffnen eines Materialdialogs in ngAfterViewChecked. Wie @ aks4it berichtete, musste ich den Code in ein setTimeout einbinden, damit es funktioniert.

Ich habe das gleiche Problem mit Version 4.01
ng-version = "4.0.1

Gleiches hier mit Winkel 4.4.6

Behebung mit this.changeDetector.detectChanges();

Ich habe diesen Plunker mit Vorlagenvariablen geschrieben und verstehe nicht, warum ich ExpressionChangedAfterItHasBeenCheckedError habe. Wenn ich die Reihenfolge in meinen Komponenten ändere, verschwindet der Fehler:

https://plnkr.co/edit/Mc0UkTR2loI7wgmLAWtX

Ich habe changeDetector.detectChanges ausprobiert, funktioniert aber nicht

@AlexCenteno ... weil die Auswertungslogik von oben nach unten ist ... und die Eigenschaft value von comp1 @Input() public value:String=null; und dann unter Verwendung der Referenz von zurückgesetzt wird comp2.value ... <div comp1 [value]="comp2.value"></div> der inzwischen über seinen eigenen @Input() auf Hello @Input() ... alles mit einem CD-Zyklus ... also die wiederholte Überprüfung Wenn die Eingaben für untergeordnete Komponenten dieselben sind wie zu Beginn des CD-Zyklus im Entwicklungsmodus, wird die Änderung der Eigenschaft value auf comp1 .

hi @ mlc-mlapis danke für deine zeit. Es gibt also keine Möglichkeit, den Fehler zu vermeiden? Ich denke, es ist etwas, worüber ich mir keine Sorgen machen sollte, wenn ich enableProdMode aufrufe.

@AlexCenteno ... ja, im Prod-Modus wird die Prüfung nach dem CD-Zyklus nicht aufgerufen ... aber das bedeutet nicht, dass Sie damit zufrieden sein sollten. Sie sollten eine andere Logik anwenden, um die untergeordneten Komponenten value . Es gibt auch ein Problem, dass <div> keine Eigenschaft value . Warum verwenden Sie überhaupt eine Attributkomponente? Warum nicht einfach:

<comp1 [value]="comp2.value"></comp1>
<comp2 #comp2 value="Hello"></comp2>

denn dann wäre die Verwendung von @Output() für <comp2> in Ordnung und es würde Ihnen ermöglichen, [value] für comp1 ohne Fehler zu aktualisieren.

Verwenden Sie [email protected] mit angular@5 standart store.select werfen Sie die Warnung ExpressionChangedAfterItHasBeenCheckedError im Dev-Modus und arbeiten Sie falsch im Prod-Modus. Versand und Auswahl erfolgen auf verschiedenen Ebenen / Containern.

@Component({
  ...
  template `
  ...
      <div [ngClass]="{
        'home__sidenav': true,
        'home__sidenav--active': (isActiveSidenavMenu$ | async)
      }">
  ...
  `
})
export class HomeContainer {
  isActiveSidenavMenu$ = this.store.select(fromHome.isActiveSidenavMenu);
  ...
}

Dieser Ansatz entfernt die Warnmeldung, scheint jedoch komplizierter zu sein:

@Component({
  ...
  template `
  ...
      <div [ngClass]="{
        'home__sidenav': true,
        'home__sidenav--active': isActiveSidenavMenu
      }">
  ...
  `
})
export class HomeContainer {
  isActiveSidenavMenu$ = this.store.select(fromHome.isActiveSidenavMenu);
  isActiveSidenavMenu;

  ngOnInit() {
    this.isActiveSidenavMenu$.subscribe(res => {
      this.isActiveSidenavMenu = res;
      this.cd.detectChanges();
    });
  }
}

Gibt es eine Idee, wie man dieses Problem besser lösen kann?

@rimlin hast du versucht, den Shop direkt zu abonnieren?

ngOnInit() {
  this.store.select(fromHome.isActiveSidenavMenu)
    .subsbrice(res => {
      this.isActiveSidenavMenu = res;
    });
}

Ich glaube, ich hatte ein ähnliches Problem. und durch Vermeiden von async in der Vorlage wurde das Problem gelöst.

@ piq9117 danke für den Rat, habe deine Lösung ausprobiert, es scheint klarer mit weniger Code zu sein, aber hier muss auch this.cd.detectChanges(); aufgerufen werden, sonst wird die Ansicht nicht aktualisiert.

ngOnInit() {
    this.store.select(fromHome.isActiveSidenavMenu).subscribe(res => {
      this.isActiveSidenavMenu = res;
      this.cd.detectChanges();
    });
}

Ich benutze Angular 5.2, ich habe so etwas gemacht. Funktioniert bei mir

constructor(private changeDetector: ChangeDetectorRef) {}

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

Mit Angular 5.2, behoben mit detectChanges ()

Ja, wir haben dies auch mit der Route detectChanges () behoben (Angular 5.1). Ich bin mit vielen anderen hier, obwohl dies der Meinung ist, dass dies immer noch nur eine Problemumgehung ist und auf lange Sicht nicht als Antwort betrachtet werden sollte. Es sollte einen weiteren Lebenszyklus-Hook geben, der verwendet werden kann.

Das Auslösen eines völlig neuen Änderungserkennungszyklus, um solche Änderungen zu ermöglichen, scheint einfach nicht optimal zu sein.

Dies scheint immer weiter zu gehen, obwohl alle Antworten und Ratschläge bereits oben veröffentlicht wurden.

  1. Der richtige Weg, dies zu beheben, besteht darin, Ihre Komponenten und die Datenverarbeitung neu zu strukturieren / umzustrukturieren, um mit einem einzigen Änderungserkennungsdurchlauf von oben nach unten zu arbeiten. Dies bedeutet, dass keine untergeordnete Komponente einen Wert ändern darf, der in der Vorlage einer übergeordneten Komponente verwendet wird. Bewerten Sie neu, was Sie erstellt haben, und stellen Sie sicher, dass die Daten nur in eine Richtung im Komponentenbaum fließen. Dies kann so einfach sein, dass Sie Ihren Code in einigen Fällen aus ngAfterViewInit in ngOnInit verschieben.
  2. this.changeDetectorRef.detectChanges(); ist die offizielle und anerkannte Methode, um dies in weniger als 5% der Fälle zu handhaben, in denen der erste Schritt problematisch ist.

Weitere Hinweise:

  1. Seien Sie sehr vorsichtig, wenn Sie etwas in ngAfterViewInit tun, da das Ändern von Werten, die im DOM verwendet werden, diesen Fehler verursachen kann.
  2. Seien Sie sehr vorsichtig, wenn Sie einen der Check oder Checked Lifecycle-Hooks verwenden, da diese bei jedem Änderungserkennungszyklus aufgerufen werden können.
  3. setTimeout kann dies umgehen, aber die beiden oben genannten Lösungen werden bevorzugt.
  4. Wenn Sie diesen Fehler im Entwicklungsmodus ignorieren und froh sind, dass der Produktionsmodus den Fehler "behebt", ist er nicht gültig, wie oben erläutert. Diese Überprüfungen werden nicht im Prod-Modus durchgeführt, aber Ihr Prod-Modus-Code lässt Änderungen immer noch unentdeckt und führt dazu, dass die Ansicht und die Daten nicht synchron sind. Dies kann in einigen Fällen harmlos sein, kann jedoch zu Daten- / Ansichtsbeschädigungen und schlimmeren Problemen führen, wenn es ignoriert wird.
  5. Ein Weg Datenfluss hat sich in Angular nicht wirklich geändert, daher ist es nicht allzu hilfreich, zu posten, dass Sie dies in Version X von Angular getroffen haben.
  6. Das Hinzufügen weiterer Lifecycle-Hooks oder -Zustände ist hierfür keine Lösung. Entwickler würden nur Code hinzufügen, der den Einwegdatenfluss in diese Hooks verletzt, und denselben Fehler auslösen.

Denken Sie zum Schluss daran, dass dieser Fehler kein Problem mit Angular anzeigt. Dieser Fehler soll Sie darüber informieren, dass Sie in Ihrem Code etwas falsch gemacht haben und dass Sie gegen das Einweg-Datenflusssystem verstoßen, das Angular schnell und effizient macht.

Die obigen Beiträge und viele Blog-Beiträge befassen sich eingehender damit und sind lesenswert, da Sie dieses Einweg-Datenflussmodell verstehen und wissen sollten, wie Sie Komponenten erstellen und Daten darin übergeben.

@Splaktar Wäre es besser, dieses Problem zu sperren (und mich zu löschen), um den obigen Kommentar hervorzuheben? Der Thread wird bereits zu lang und die meisten wiederholten sich nur. 😃

@Splaktar Sie machen diesen Punkt "Dies bedeutet, dass keine

Angenommen, Sie haben eine Containerkomponente, die Navigation, Seitentitel usw. enthält, und sie lädt eine Sammlung von Unterkomponenten, von denen jede ihre eigenen Unterkomponenten laden kann. Die in den Container geladenen Komponenten ändern sich basierend auf Daten, und die von ihnen geladenen Unterkomponenten ändern sich basierend auf Daten. Jede dieser Unterkomponenten muss in der Lage sein, dem übergeordneten Container Informationen darüber zurückzugeben, was sie sind, damit der übergeordnete Container dem Benutzer möglicherweise auch das entsprechende Nav der obersten Ebene anzeigen kann (möglicherweise Breadcrumb-Trail oder ähnliches) als Informationen, die in Titeln verwendet werden können, um auf Containerebene zu identifizieren, was in die Ansicht geladen wird.

In dieser meiner Erfahrung nach äußerst verbreiteten Architektur würde ich einen gemeinsamen staatlichen Dienst verwenden, bei dem sich die Unterkomponenten registrieren und die übergeordnete Komponente abonnieren würde, damit die Kinder die Eltern und die Eltern erziehen können kann die entsprechenden Informationen anzeigen.

Dies folgt keinem Bottom-up-Ansatz, da die Eltern alle relevanten Daten vom Dienst abrufen und alle von den untergeordneten Komponenten benötigten Informationen über eine Einwegkommunikation nach unten drücken würden.

Dies scheint dem zu widersprechen, was Sie oben vorgeschlagen haben, und für mich ist dies die Ursache des Problems. Wenn sich die untergeordnete Komponente beim Dienst registriert, gibt die übergeordnete Komponente den Fehler aus.

Ist das falsch

Und vergessen Sie niemals, dass es einen genehmigten Fehler gibt:
https://github.com/angular/angular/issues/15634

@alignsoft ... hast du eine einfache Reproduktion deines Falles und des Problems als Stackblitz? Weil es so aussieht, als ob etwas anderes den Fall beeinflussen sollte als nur die von Ihnen beschriebene Logik.

@trotyl Die Lösungen von @Splaktar beziehen sich nicht auf mein einfaches Problem hier https://github.com/angular/angular/issues/17572#issuecomment -311589290 oder?

@ Martin-Wegner ... in deinem Fall reicht es aus, ngAfterViewInit in ngOnInit hook zu ändern.

@alignsoft , wie @ mlc-mlapis sagte, wäre ein Stackblitz-Beispiel sehr hilfreich, um die richtige Architektur für diesen Fall zu demonstrieren. Dies ist mit den richtigen Diensten, Observablen, Lifecycle-Hooks usw. sehr gut möglich. Dieser spezielle Fall wäre auch ein gutes Thema für StackOverflow.

@Splaktar Sobald ich meine aktuelle Frist von meinem Schreibtisch habe, werde ich ein Projekt

@ mlc-mlapis wow danke, es funktioniert :)

@alignsoft , heute habe ich eine App erstellt, die sich genau so verhält, wie Sie es beschrieben haben. @ mlc-mlapis, das abgespeckte Beispiel finden Sie auf stackblitz . Wenn Sie auf der linken Seite auf "CMS-System" klicken, wird die Ausnahme ExpressionChangedAfterItHasBeenCheckedError ausgelöst.

In diesem Beispiel fungiert die admin.component als übergeordnete Komponente, die für drei Dinge verantwortlich ist:

  • Anzeige eines linken Navigationsgeräts
  • Ein Top-Ticker, mit dem Unterkomponenten ihre eigene Tickernachricht anzeigen können
  • Ein Hauptinhaltsabschnitt, in dem unterkomponentenspezifische Daten über <router-outlet></router-outlet> angezeigt werden.

Übergeordnete Komponente

<div class="ticker-container" *ngIf="tickedMessage !== ''">
  <h1>{{tickedMessage}}</h1>
  <button type="button" (click)="tickedMessage = ''">
    close
  </button>
</div>

<div class="side-nav">
  <h2>side nav</h2>
  <ul>
    <li><a routerLink="/">dashboard</a></li>
    <li><a routerLink="/apps/thirdpartycms">CMS System</a></li>
  </ul>
</div>
<div class="main-content-container">
  <router-outlet></router-outlet>
</div>
export class AdminComponent implements OnInit, OnDestroy {
  private _tickedMessageSubscription: Subscription;

  tickedMessage: string = '';

  constructor(
    private router: Router,
    private adminService: AdminService
  ) { }

  ngOnInit() {
    /* 
      On the side nav if you click on CMS System, this piece of code throws the exception: 
      "ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed 
       after it was checked. Previous value: 'false'. Current value: 'true'.""
    */
    this._tickedMessageSubscription = this.adminService.tickedMessageAnnounced$.subscribe((tickedMessage: string) => {
      this.tickedMessage = tickedMessage;
    });
  }

  ngOnDestroy() {
    this._tickedMessageSubscription.unsubscribe();
  }
}

Bei der Untersuchung, wie Daten bei Verwendung von <router-outlet></router-outlet> wieder an die übergeordnete Komponente übertragen werden können, habe ich gelesen, dass die Router-Outlet-Direktive endet, wenn ich @Output zum Zurücksenden von Daten an die übergeordnete Komponente verwende Behandlung des Ereignisses. Da es sich um ein benutzerdefiniertes Ereignis handelt, kann die Router-Outlet-Direktive nicht damit umgehen. Also habe ich diese Methode übersprungen. Nachdem ich bei angular.io über Shared Services gelesen hatte, schrieb ich meine eigenen:

Shared Service

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';

@Injectable()
export class AdminService {

  private _tickedMessageAnnounced = new Subject<string>();

  tickedMessageAnnounced$ = this._tickedMessageAnnounced.asObservable();

  announceTickedMessage(tickedMessage: string) {
    this._tickedMessageAnnounced.next(tickedMessage);
  }
}

Sobald eine der untergeordneten Komponenten this.adminService.announceTickedMessage(this._tickedMessage); :

Untergeordnete Komponente

import { Observable } from 'rxjs/Observable';
import { Component, ViewChild, OnInit, Inject } from '@angular/core';
import { AdminService } from '../../../core/admin/admin.service';

@Component({
  selector: 'cms',
  templateUrl: './thirdparty-cms.component.html',
  styleUrls: ['./thirdparty-cms.component.scss'],
})
export class ThirdPartyCmsComponent implements OnInit {
  private _tickedMessage: string;
  constructor(private adminService: AdminService) { }

  ngOnInit(): void {
    this._tickedMessage = 'Please do not create an entry for a page URL that does not exist in the CMS system';

    this.adminService.announceTickedMessage(this._tickedMessage);
  }
}

Die übergeordnete Komponente hat eine ExpressionChangedAfterItHasBeenCheckedError -Ausnahme ausgelöst, weil versucht wurde, eine ihrer öffentlichen Eigenschaften mit dem angekreuzten Nachrichtenwert zu aktualisieren, der von der untergeordneten Komponente gesendet wurde:

Übergeordnete Komponente (löst eine Ausnahme aus)

export class AdminComponent implements OnInit, OnDestroy {
  private _tickedMessageSubscription: Subscription;

  tickedMessage: string = '';

  constructor(
    private router: Router,
    private adminService: AdminService
  ) { }

  ngOnInit() {
    /* 
      On the side nav if you click on CMS System, this piece of code throws the exception: 
      "ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed 
       after it was checked. Previous value: 'false'. Current value: 'true'.""
    */
    this._tickedMessageSubscription = this.adminService.tickedMessageAnnounced$.subscribe((tickedMessage: string) => {
      this.tickedMessage = tickedMessage;
    });
  }

  ngOnDestroy() {
    this._tickedMessageSubscription.unsubscribe();
  }
}

Das Problem mit ExpressionChangedAfterItHasBeenCheckedError wurde behoben, indem der Abonnement-Rückruf asynchron ausgeführt und auf die angekreuzte Nachricht gewartet wurde:

Übergeordnete Komponente (mit asynchronem Warten)

export class AdminComponent implements OnInit, OnDestroy {
  private _tickedMessageSubscription: Subscription;

  tickedMessage: string = '';

  constructor(
    private router: Router,
    private adminService: AdminService
  ) { }

  ngOnInit() {
    /* 
      This clears the ExpressionChangedAfterItHasBeenCheckedError exception.
    */
    this._tickedMessageSubscription = this.adminService.tickedMessageAnnounced$.subscribe(async (tickedMessage: string) => {
      this.tickedMessage = await tickedMessage;
    });
  }

  ngOnDestroy() {
    this._tickedMessageSubscription.unsubscribe();
  }
}

Aus der WPF-Welt kommend scheint es, als müssten wir den UI-Thread anweisen, auf den Observable-Abonnement-Rückruf zu warten, da Observables asynchron ausgeführt werden.

Ich fange gerade mit Angular an, also haben Sie bitte etwas Mitgefühl mit meinen Angular-Fähigkeiten: P.

@ktabarez Danke, das hat mir sehr geholfen!

@ktabarez Danke! Das scheint gut zu funktionieren! Ich habe das Abonnement in der übergeordneten Komponente in eine Zeitüberschreitung eingeschlossen, die ebenfalls funktionierte, sich aber schmutzig anfühlte.

Ich sehe, dass beim Abfragen des Redux-Status garantiert ist, dass er liefert, aber beim Start wie beim Einfügen in ngOnInit im Gegensatz zu Konstruktoren

@ktabarez Vielen Dank!

Ihre async ... await in subscribe Lösung funktioniert.

@ktabarez Ihre Lösung

Frage: Warum sollten wir eine asynchrone / wartende Berechnung einer Eigenschaft für ein Observable durchführen müssen, das Daten vom Back-End erhält, die sich möglicherweise häufig ändern? Was ist mit ngClass notwendig? Ich bekomme das, wenn ich ein {beobachtbares | benutze asynchrone} Pipe. Das Async / Warten ist also nicht der beste Apprach für mich. (oder die asynchrone Pipe ist nicht der beste Ansatz)

Ich habe dieses Problem, bei dem meine übergeordnete Komponente mehrere untergeordnete Komponenten hat. Eine der untergeordneten Komponenten verfügt über eine Eingabe, bei der Daten aus der übergeordneten Komponenteneigenschaft benötigt werden und die Eigenschaft ihre Daten aus einem Observable / Promise abruft (beide ausprobiert).

parent.component.html

<mat-tab-group>
   <mat-tab>
      <app-child-1></app-child-1>
   </mat-tab>
   <mat-tab>
      <app-child-2></app-child-2>
   </mat-tab>
   <mat-tab>
      <app-child-3 [datasource]="data"></app-child-3>
   </mat-tab>
</mat-tab-group>

parent.component.ts

// ... omitted...
data: any;

ngOnInit() {
   this.service1.getMethod(some_id).then(data => this.data = data);
}

Ich bin auf alle Lösungen gestoßen, die im Thread gefunden wurden. Aber in meinem Fall funktioniert nichts. Glücklicherweise haben einige angedeutet, dass dies ein Problem ist, weil ein DOM manipuliert wurde, beispielsweise als Ausdruck für _ (ngIf) _.

Um dies zu vermeiden, versuche ich mit ng-template , ng-container und ngTemplateOutlet zu experimentieren .

<ng-container *ngTemplateOutlet="data ? content : loading"></ng-container>

<ng-template #content>
   <mat-tab-group>
      <mat-tab>
         <app-child-1></app-child-1>
      </mat-tab>
      <mat-tab>
         <app-child-2></app-child-2>
      </mat-tab>
      <mat-tab>
         <app-child-3 [datasource]="data"></app-child-3>
      </mat-tab>
   </mat-tab-group>
</ng-template>

<ng-template #loading>Loading your component. Please wait</ng-template>

Ich konnte dies lösen, ohne ChangeDetectorRef oder setTimeout()

Bei mir trat dieser Fehler beim Ein- / Ausblenden des Feldes gemäß der Bedingung auf. Ich konnte ihn beheben, nachdem ich die Werte der Feldeinstellung angewendet hatte:

this.form.get ('field').updateValueAndValidity();

Ich habe versucht, dies mit einem Mat-Dialog zu tun, der auf init geöffnet wird, und ich habe buchstäblich jede Lösung ausprobiert, die ich in diesem Thread gesehen habe (Timeout festlegen, Auflösung versprechen, beobachtbare Pipe, nach View Init, nach Content Init). und Kombinationen darin. Funktioniert immer noch nicht. Dann habe ich einen @ Splaktar- Beitrag darüber gesehen, wie dies den Einweg-Datenfluss verletzt. ngrx buchstäblich ein Flag gesetzt, um den Dialog zu öffnen, und das abonniert, was anfangs falsch ist, und ich erhalte immer noch diesen Fehler. Was um alles in der Welt mache ich? Gibt es buchstäblich keine Möglichkeit, einen modalen Dialog zu öffnen, ohne ihn an ein völlig separates Ereignis anzuhängen?

In on init:
this.store.pipe( select(getShouldLogin), ).subscribe((shouldLogin: boolean) => { if (shouldLogin) { this.openLoginDialog(); } }); this.checkUserId();

Hilfsfunktionen:
checkUserId() { const id = this.cookies.getUserId(); if (!id || id === 'undefined') { this.connApi.setShouldLogin(true); } }
openLoginDialog() { const dialogRef = this.dialog.open(LoginDialogComponent, { width: '400px', height: '300px', }); dialogRef.afterClosed().subscribe(result => this.handleLogin(result)); }

Verwenden von Winkel 6.0.0-rc.1

Ich verwende Angular mit ngrx und habe diesen Fehler nach dem Absenden eines Formulars erhalten.
durch Einstellung behoben
ChangeDetectionStrategy.OnPush
auf Formularkomponente

immer noch das Problem. versuchte alle möglichen Problemumgehungen. setTimeout funktioniert beim ersten Mal, aber das anschließende Auslösen von dialog.open führt zum gleichen Fehler. Irgendein Status dazu?

Ich stehe vor dem gleichen Problem. Ich habe alles versucht, aber es scheint, dass dieses Problem bei einem Datenfluss in eine Richtung auftritt.
Hier versuche ich ausgewähltewoids zu aktualisieren. wo das Problem löst, aber der gleiche Fehler auftritt.

        <p-row> <p-column class="text-left" footer="{{selectedWoids.length}} {{getWoidString(selectedWoids.length)}} selected out of {{getTotalCounts()}} {{getWoidString(getTotalCounts())}}" colspan="11"></p-column> </p-row>

private setSelectedWoidsCount () {
if (this.isSelectAllWoids) {
this.selectedWoids = this.allWoids;
}}
}}

Weil Sie die Rendering-Pipeline von Angular ...

Ich sehe ähnliche "ExpressionChanged ..." - Fehler nach dem Wechsel von 4.1.2 zu 4.2.3 .

In meinem Fall habe ich zwei Komponenten, die über einen Dienst interagieren. Der Service wird über mein Hauptmodul bereitgestellt und ComponentA wird vor ComponentB .

In 4.1.2 funktionierte die folgende Syntax ohne Fehler einwandfrei:

_ComponentA Vorlage: _

<ul *ngIf="myService.showList">
...

_ComponentB Klasse: _

ngOnInit() {
  this.myService.showList = false; //starts as true in the service
  ...
}

In 4.2.3 muss ich die Vorlage von ComponentA wie folgt ändern, um den Fehler "ExpressionChanged ..." zu vermeiden:

_ComponentA Vorlage: _

<ul [hidden]="!myService.showList">
...

Ich versuche immer noch herauszufinden, warum dies gerade erst zu einem Problem geworden ist und warum der Wechsel von *ngIf zu [hidden] funktioniert.

Haben Sie herausgefunden, wie es funktioniert hat, als Sie von ngIf zu [hidden] gewechselt haben?

Gibt es in Angular 6 schon eine Lösung für dieses Problem?

@alokkarma ... zu alt ... du solltest es mindestens auf Angular 6 oder 5 migrieren. Ihr Beispielcode sieht jedoch klar aus ... Sie ändern die Serviceeigenschaft in der untergeordneten Komponente B und dies wirkt sich auf ein gewisses Verhalten in der untergeordneten Komponente A aus. Beide untergeordneten Komponenten befinden sich im selben übergeordneten Element, sodass alle drei Komponenten zusammen in verarbeitet werden Beziehung in einem CD-Zyklus. Was erwartest du?

Die Tatsache, dass der gleiche Fall in Version 4.1.2 funktioniert hat, hängt mit einigen Fehlern zusammen, die in späteren Versionen, einschließlich 4.2.3, behoben wurden.

Ich verwende Angular 6. Ich verwende einen MessageService, um zwischen meiner Authentifizierungskomponente und meiner App-Komponente zu kommunizieren und unterschiedliche Inhalte der Navigationsleiste anzuzeigen, wenn der Benutzer angemeldet ist (oder nicht).

Abgesehen von diesem Fehler funktioniert es einwandfrei!
Ich habe andere Lösungen wie EventEmitter ausprobiert, aber es funktioniert nicht! oder ich bekomme den gleichen Fehler.

@dotNetAthlete ... zeigt eine einfache Reproduktionsdemo auf Stackblitz. Ohne den richtigen Code darüber zu sprechen ist schwierig.

@dotNetAthlete Ich verwende denselben grundlegenden Mechanismus, bei dem ich einen

Es gab immer einen Fehler "Ausdruck geändert", als der Container den Wert initialisierte und die untergeordnete Komponente ihn sofort aktualisierte. Deshalb mache ich dies jetzt im übergeordneten / Container:

    this.stateSvc.currentPageTitle$
      .subscribe(
        (async (pageTitle) => {
          this.pageTitle = await pageTitle;
        }))

Wo der Staatsdienst dies hat:

  // Store
  private currentPageTitleStore = new BehaviorSubject<string>("");

  // Getter (as Observable)
  public currentPageTitle$ = this.currentPageTitleStore.asObservable();

  // Setter
  public setCurrentPageTitle(pageTitle: string) {
    this.currentPageTitleStore.next(pageTitle);
  }

Dies beseitigt das Problem. Diese Lösung basiert auf einigen hilfreichen Rückmeldungen von anderen in diesem Thread.

@alignsoft - schöne Lösung - Problem in Angular 6 App behoben.

Ich sehe dies auf Seite Reload auf Winkel 7 jetzt ...
Ich setze einen untergeordneten Komponentenwert für Eltern ngAfterViewInit
Musste dies auf der untergeordneten Komponente tun

  public activate() {
    setTimeout(() => this.active = true);
  }

Ich habe die Lösung in diesem Problem-Thread https://github.com/angular/angular/issues/10762 gefunden
Nachdem ich den AfterContentInit Lebenszyklus-Hook verwendet habe, verschwindet der Fehler.

@alignsoft , nur zu Ihrer Änderung hinzufügen, da wir ein BehavioralSubject anstelle eines Betreffs verwenden,

Ich habe es wie folgt verfeinert:

\\ Component
export class AppComponent implements OnInit {
  isLoading: Boolean;

  constructor(private loaderService: LoaderService) { }

  ngOnInit(){
    this.loaderService.isLoading.subscribe(async data => {
      this.isLoading = await data;
    });
  }
}
\\ Service
@Injectable({
  providedIn: 'root'
})
export class LoaderService {
  // A BehaviorSubject is an Observable with a default value
  public isLoading: BehaviorSubject<Boolean> = new BehaviorSubject(false);
  constructor() {}
}
\\ Any other component or in my case, an interceptor that has the LoaderService injected
this.loaderService.isLoading.next(true);

Aber ich stimme @daddyschmack zu , ich möchte jede Ressource erhalten, die auf Informationen bezüglich der oben genannten Korrekturen verweist ( cdr.detectionChanges() oder async await oder aftercontentchecked ), warum [hidden] Attribut *ngIf

@acidghost Danke für diesen Link, er hat mein Problem gelöst. Ich hatte es tatsächlich aufgegeben, das Problem in einem Bereich meiner Anwendung zu beheben, aber als es in einem neuen Bereich erneut auftrat ...

Dieses Problem wurde aufgrund von Inaktivität automatisch gesperrt.
Bitte reichen Sie ein neues Problem ein, wenn Sie auf ein ähnliches oder verwandtes Problem stoßen.

Lesen Sie mehr über unsere Richtlinien zum automatischen Sperren von Konversationen .

_Diese Aktion wurde automatisch von einem Bot ausgeführt._

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen