编辑:稍微改进了 stackblitz,以便人们可以并排比较它。
对于 Angular 17+,我想使用新的模板语法来迁移我的项目,这似乎有一个奇怪的行为,而且我还没有看到任何人谈论它。在旧的
*ngFor
循环中使用removeAt删除项目似乎工作得很好。然而,当我在 @for
中尝试相同的操作时......无论索引是否实际上准确(您可以控制台记录它,它确实每次都指向正确的控件),但使用removeAt它只是继续删除数组中的最后一项。我是不是理解错了@for
?我在这篇文章的末尾添加了对我的问题的最小重现,作为堆栈闪电战
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
FormArray,
ReactiveFormsModule,
UntypedFormBuilder,
} from '@angular/forms';
import 'zone.js';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
imports: [ReactiveFormsModule, CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
template: `
<form [formGroup]="baseSearchForm">
<div>
<input type="text" formControlName="search" placeholder="Search for ...">
</div>
<div style="margin-top: 1rem; background: lightgray; padding: 1rem; " formArrayName="searchParams">
<!-- removeFilter here will always successfully delete the right control -->
<!-- <div *ngFor="let control of searchParams.controls; let i = index;">
<div style="display: flex; flex-direction: row;" [formGroupName]="i">
<input type="text" formControlName="field" placeholder="... where column ...">
<input type="text" formControlName="operator" placeholder="... is ...">
<button *ngIf="i > 0" (click)="removeFilter(i)">Remove</button>
</div>
</div> -->
<!-- removeFilter will only delete the last element of the array, regardless of the index -->
@for(control of searchParams.controls; track $index;) {
<div style="display: flex; flex-direction: row;" [formGroupName]="$index">
<input type="text" formControlName="field" placeholder="... where column ...">
<input type="text" formControlName="operator" placeholder="... is ...">
<button *ngIf="$index > 0" (click)="removeFilter($index)">Remove</button>
</div>
}
</div>
<button style="margin-top: 1rem" (click)="addFilter()">Add Filter</button>
</form>
`,
})
export class App {
fb = inject(UntypedFormBuilder);
baseSearchForm = this.fb.group({
search: [''],
searchParams: this.fb.array([
this.fb.group({
field: [0],
logicalOperator: [''],
operator: [''],
type: [''],
values: [],
}),
]),
});
get searchParams() {
return this.baseSearchForm.get('searchParams') as FormArray;
}
removeFilter(index: number) {
this.searchParams.removeAt(index);
}
addFilter() {
this.searchParams.push(
this.fb.group({
field: [this.searchParams.length],
logicalOperator: [''],
operator: [''],
type: [''],
values: [],
})
);
}
}
bootstrapApplication(App);
我将给出与 GitHub 问题相同的答案:
这是 dom 有状态的情况之一,您不应该使用索引作为跟踪键。
ngFor
指令默认使用indentity作为跟踪键,您可以通过跟踪control
来执行相同的操作:
@for(control of searchParamsAlt.controls; track control)