Angular 17 - 尽管调用了 detectorChanges,仍抛出 ExpressionChangedAfterItHasBeenCheckedError

问题描述 投票:0回答:1

我在 Angular 及其变更检测方面遇到了一个小问题。我有一个非常简单的表单,允许添加其他输入容器,但每次单击添加按钮时,我都会在控制台中抛出 ExpressionChangedAfterItHasBeenCheckedError 。 当使用标准 ngFor 时,控制台中会抛出错误,但仍会显示新输入。 然而,当使用 Angular 的新 @for 选项时,我在控制台中抛出了错误,但它也没有显示。 在这两种情况下,我都确保调用了 detectorChanges (也尝试过 markForCheck),但这没有什么区别。

  public properties: Map<number, string> = new Map<number, string>();

  public addProperty() {
    const id: number = this.properties.size ?
      Array.from(this.properties.keys()).reduce((a, b) => a > b ? a : b) + 1 :
      1;

    this.properties.set(id, 'placeholder');
    this.changeDetectorRef.detectChanges();
  }
      <button class="btn btn-primary" (click)="addProperty()">+</button>

      <div class="d-flex flex-column">
        <ng-container *ngFor="let attribute of properties.entries()">
          <span>{{ attribute[0] }}</span>
        </ng-container>
      </div>

我非常感谢您对这个问题的任何见解,提前致谢。

我尝试过使用 ngFor 以及 Angular 的新 @for 选项,两者之间的唯一区别是,当使用 @for 时,除了控制台错误之外,不会显示新数据。 我也尝试过手动调用变更检测器,但没有任何影响。

angular ngfor angular-changedetection change-detector-ref
1个回答
0
投票

Angular

ngFor
是专门为数组设计的,所以我猜由于通过引用存储地图,更改检测会变得混乱。您可以在输入到
ngFor
之前将其转换为数组,这也消除了更改检测问题。请在下面找到一个工作示例!

如果您特别需要键或值,可以访问

properties.keys()
properties.values()

import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule],
  template: `
    <button class="btn btn-primary" (click)="addProperty()">+</button>
    <div class="d-flex flex-column">
      {{properties.entries() | json}}
      <ng-container *ngFor="let attribute of mapEntriesToArray;trackBy: trackByFn ">
        <span>{{ attribute[0] }}</span>
      </ng-container>
    </div>
  `,
})
export class App {
  public properties: Map<number, string> = new Map<number, string>();

  constructor(private changeDetectorRef: ChangeDetectorRef) {}

  get mapEntriesToArray() {
    return Array.from(this.properties.entries());
  }

  public addProperty() {
    const id: number = this.properties.size
      ? Array.from(this.properties.keys()).reduce((a, b) => (a > b ? a : b)) + 1
      : 1;

    this.properties.set(id, 'placeholder');
  }

  trackByFn(index: number, item: any) {
    return index;
  }
}

bootstrapApplication(App);

堆栈闪电战

© www.soinside.com 2019 - 2024. All rights reserved.