I have an Angular Material Expansion Panel Query list:
@ViewChildren(MatExpansionPanel)
matExpansionPanelQueryList: QueryList<MatExpansionPanel>;
and a simple array:
questions: [];
The Expansion Panels are generated with an *ngFor
: simplified for example:
<ng-container *ngFor="let question of questions>
<mat-expansion-panel
...
When I extend the questions array, I want to open up the last expansion panel.
extendQuestion() {
this.matExpansionPanelQueryList.changes.subscribe(
change => {
change.last.open();
}
);
this.questions.push('some-new-item');
}
This works just fine - I insert an item to the array,
the ExpansionPanels get's re-rendered, a new Panel gets created and it actually opens up - my problem is that it generates the following error in the console:
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has
changed after it was checked. Previous value: 'mat-expanded: false'. Current
value: 'mat-expanded: true'.
Is there any way to avoid this?
I have tried using changeDetectorRef
and markForCheck()
in the subscription, but the error message did not go away (and honestly, I am 100% sure what's the exact problem here).
Update: Stackblitz example of the issue (click the "+" button)
From angularindepth:
This is a cautionary mechanism put in place to prevent inconsistencies between model data and UI so that erroneous or old data are not shown to a user on the page.
A running Angular application is a tree of components. During change detection Angular performs checks for each component which consists of the following operations performed in the specified order:
After each operation Angular remembers what values it used to perform an operation. They are stored in the oldValues property of the component view.
You might want to trigger the lifecycle hook of your component before the DOM update operation..
That should work for you:
You can add a constructor
for changedetection (cd) and call it after change.last.open();
import {ChangeDetectorRef, Component, OnInit, QueryList, ViewChildren} from '@angular/core';
import {MatDialog, MatExpansionPanel} from '@angular/material';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
questions = ['first', 'second'];
constructor(private cd: ChangeDetectorRef) {
}
@ViewChildren(MatExpansionPanel) matExpansionPanelQueryList: QueryList<MatExpansionPanel>;
extendQuestion() {
this.matExpansionPanelQueryList.changes.subscribe(
change => {
change.last.open();
this.cd.detectChanges();
}
);
this.questions.push('some-new-item');
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With