【问题标题】:Mat chip list select single ExpressionChangedAfterItHasBeenCheckedErrorMat芯片列表选择单个ExpressionChangedAfterItHasBeenCheckedError
【发布时间】:2020-12-30 23:39:27
【问题描述】:

我在一个芯片列表中显示一些芯片:

<mat-chip-list>
  <mat-chip *ngFor="let rockBand of this.rockBands"
   [disableRipple]="true"
   [selected]="rockBand.selected"
   (click)="this.toggleSelection(rockBand)">{{ rockBand.name }}</mat-chip>
</mat-chip-list>

当用户点击芯片时,会调用以下函数:

public toggleSelection(rockBand: RockBand): void {
  rockBand.selected = !rockBand.selected;
}

但是,切换所选值会导致以下错误:
ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。 'attr.aria-selected' 的先前值:'true'。当前值:'null'。

我知道mat-chip-list 有一个名为multiple 的输入属性,它指示是否应允许用户选择多个芯片。在我的场景中,用户一次只能选择一个芯片,就像单选按钮一样,如果已经选择了芯片,则取消选择它。将点击功能更改为以下内容确实有效:

public toggleSelection(rockBand: RockBand): void {
  const shouldSelect = !rockBand.selected;
  this.rockBands.forEach(band => band.selected = false);
  rockBand.selected = shouldSelect;
}

此解决方案不是最理想的,因为这需要遍历所有条目并将所选值重置为 false。 是否有另一种可能更好的方法来解决此问题?

【问题讨论】:

    标签: angular angular-material


    【解决方案1】:

    两个疏忽:

    1. 永远不要使用模板变量,因为 this.rockBands 只是 rockBands 效果很好。
    2. 第一个toggleSelection 中的逻辑不正确。您正在切换点击芯片的selected 标志,但没有重置已选择芯片的标志。下次如果用户想再次选择该芯片,他们需要点击两次。 (我会说第二种方法更好)

    TL;DR

    添加以下代码:

     import { ChangeDetectorRef, AfterContentChecked} from '@angular/core';
          constructor(private cdref: ChangeDetectorRef) { }
                    
                      ngAfterContentChecked() {
                        this.cdref.detectChanges();
                      }
    

    Working example

    为什么我收到ExpressionChangedAfterItHasBeenCheckedError

    因此,变更检测背后的机制实际上是以一种同时执行变更检测和验证摘要的方式工作的。这意味着,如果我们异步更新属性,则在验证循环运行时将不会更新值,并且我们不会得到 ExpressionChanged... 错误。我们收到此错误的原因是,在验证过程中,Angular 看到的值与其在更改检测阶段记录的值不同。

    A good Read about this

    【讨论】:

    • 感谢您的快速回复!我看到 ngAfterContentChecked 生命周期钩子可以解决问题。选择和取消选择芯片的行为不一致。当我点击苹果然后点击香蕉然后回到苹果时,我必须点击两次。
    • 是的..请参阅答案中的第二点。你的神奇逻辑不对。
    • 我明白你的意思。但是,如果我更改处理单击操作的逻辑并取消选择已选择的芯片,我不需要 ngAfterContentChecked 生命周期挂钩,对吗?
    • 是的,你不需要。我举了这个例子来消除你的疑问。
    猜你喜欢
    • 2019-09-11
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多