You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用*ngFor遍历FormArray时删除元素触发错误

Angular FormArray 删除商品时出现 undefined 错误的解决

我在《Learning Angular No Nonsense》书中的FormArray示例基础上,做了购物车动态表单的改进,添加删除商品功能时触发了错误。删除商品时,模板里的{{ cart2[i].name }}和(click)="removeProduct(i)"行抛出错误:ERROR TypeError: ctx_r1.cart2[i_r4] is undefined。


问题代码

Cart.component.html

<form [formGroup]="cartForm2" (ngSubmit)="validateCart()">
  <div
    formArrayName="products"
    *ngFor="let product of cartForm2.controls.products.controls; let i = index"
  >
    <label>{{ cart2[i].name }} : </label>

    <input type="number" [formControlName]="i" />
    <button type="button" (click)="removeProduct(i)">Remove</button>
    <span *ngIf="product.touched && product.hasError('required')">
      此字段为必填项</span
    >
    <span *ngIf="product.touched && product.hasError('min')">
      数值不能小于1</span
    >
  </div>
  <p>cartForm.value : {{ cartForm2.value | json }}</p>
  <div>
  
    <button type="submit" [disabled]="!cartForm2.valid">确认</button>
  </div>
</form>

cart.component.ts

cartForm2 = new FormGroup({
  products: new FormArray<FormControl<number>>([]),
});
cart2: Product[] = []; 
ngOnInit(): void {
  this.cart2 = this.cartService.cart;
  this.cart2.forEach(() => {
    this.cartForm2.controls.products.push(
      new FormControl(1, {
        nonNullable: true,
        validators: [Validators.required, Validators.min(1)],
      })
    );
  });
}
removeProduct(index: number) {
  this.cartService.deleteProduct(index); 
  this.cart2 = this.cartService.cart
  this.cartForm2.controls.products.removeAt(index);   
  console.log(JSON.stringify(this.cart2));   
}

cart.service.ts

cart: Product[] = [];

constructor() {}

addProduct(product: Product) {
  this.cart.push(product);
}

deleteProduct(index: number) {
  this.cart.splice(index, 1);
}

错误原因

模板遍历的是cartForm2.controls.products.controls,但获取商品名称时依赖外部的cart2[i]。删除操作时,先更新cart2再移除FormArray中的控件,Angular变更检测会出现短暂不同步:此时FormArray的控件数量还未减少,而cart2已经少了一个元素,导致遍历到的索引i在cart2中找不到对应元素,抛出undefined错误。


解决方法

改用FormGroup封装每个商品的信息(名称和数量),让FormArray的每个元素都包含商品名称的FormControl,直接从FormControl中获取名称,不再依赖外部的cart2数组:

修改后的代码

cart.component.ts 部分修改

this.cart2.forEach((product) => {
  this.cartForm2.controls.products.push(
    new FormGroup({
      name: new FormControl(product.name),
      quantity: new FormControl(1, {
        nonNullable: true,
        validators: [Validators.required, Validators.min(1)],
      }),
    })
  );
});

Cart.component.html 部分修改

<label>{{ product.controls["name"].value }}</label>

修改后,模板直接从当前遍历的FormGroup中获取商品名称,避免了索引不同步的问题,删除操作时不再出现undefined错误。

内容的提问来源于stack exchange,提问作者v3geto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:12:06