MatExpansionPanel表达式经过检查后更改,错误为'mat-expanded:true'

时间:2019-02-22 08:44:40

标签: angular angular-material

我有一个Angular Material Expansion Panel查询列表:

  @ViewChildren(MatExpansionPanel)
  matExpansionPanelQueryList: QueryList<MatExpansionPanel>;

和一个简单的数组:

questions: [];

扩展面板是用*ngFor生成的:例如,简化:

   <ng-container *ngFor="let question of questions>
            <mat-expansion-panel
               ...

扩展问题数组时,我要打开最后一个扩展面板。

     extendQuestion() {
        this.matExpansionPanelQueryList.changes.subscribe(
          change => {
            change.last.open();
          }
        );

        this.questions.push('some-new-item');
      }

这很好用-我在数组中插入了一个项目,
重新渲染了ExpansionPanels,创建了一个新面板,它实际上打开了-我的问题是它在控制台中生成了以下错误:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has 
changed after it was checked. Previous value: 'mat-expanded: false'. Current 
value: 'mat-expanded: true'.

有什么办法可以避免这种情况?
我尝试在订阅中使用changeDetectorRefmarkForCheck(),但是错误消息并没有消失(老实说,我100%确信这里的确切问题是什么)。

更新Stackblitz example of the issue (click the "+" button)

3 个答案:

答案 0 :(得分:3)

来自angularindepth

  

这是一种警告机制,旨在防止模型数据和UI之间出现不一致,以免在页面上向用户显示错误或旧数据。

正在运行的Angular应用程序是一棵组件树。在进行变更检测期间,Angular会检查每个组件,其中每个组件都包含以指定顺序执行的以下操作:

  • 更新所有子组件/指令的绑定属性
  • 在所有子组件/指令上调用ngOnInit,OnChanges和ngDoCheck生命周期挂钩
  • 更新当前组件的DOM
  • 运行子组件的变化检测
  • 为所有子组件/指令调用ngAfterViewInit生命周期挂钩

每次操作后,Angular都会记住用于执行操作的值。它们存储在组件视图的oldValues属性中。

您可能希望在DOM更新操作之前触发组件的生命周期挂钩。

那应该对您有用:

您可以添加00:00:00进行变更检测(cd),并在constructor之后调用它

change.last.open();

答案 1 :(得分:0)

我找到了解决问题的方法。

通过@iLuvLogix提到的链接,强制进行更改检测解决了该问题:

    constructor(private cd: ChangeDetectorRef) {}

    this.matExpansionPanelQueryList.changes.subscribe(
      change => {
        change.last.open();
        this.cd.detectChanges();
      }
    );

答案 2 :(得分:-2)

您可以使用javascript实现解决方案
Stackblitz Demo with javascript only

更新问题数组后,您可以使用javascript
,而我正在使用 setTimeout(()=>{}, 0) 将此任务放在{{1 }}
,因此在完成DOM操作后,它会在angular之后执行。

event-loop