在《学习 Angular 不废话》一书中,有一个我尝试改进的如何使用 FormArray 的示例。此示例使用基于包含产品的购物车的动态表单,我尝试添加删除购物车中的某些产品(通过使用 FormArray 集合中的 removeAt 方法)的可能性,但出现错误。
Cart.component.html,当产品被删除时,会在 {{ cart2[i].name }} 处触发错误(“ERROR TypeError: ctx_r1.cart2[i_r4] is undefined”)并且 (click)="删除产品(i)”行:
<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')">
The field is required</span
>
<span *ngIf="product.touched && product.hasError('min')">
The field can't be lower than 1</span
>
</div>
<p>cartForm.value : {{ cartForm2.value | json }}</p>
<div>
<button type="submit" [disabled]="!cartForm2.valid">Validate</button>
</div>
</form>
cart.component.ts,从服务获取购物车并为购物车中的每个产品创建一个控件。 removeProduct 方法将删除购物车服务中的产品,使用最后的引用更新 cart2 属性,使用良好的索引删除控件:
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(id: number) {
this.cart = this.cart.filter((p) => p.id === id);
}
删除产品后,我得到
ERROR TypeError: ctx_r1.cart2[i_r4] is undefined"
:
有什么想法吗?
您从
cart2
数组之前的 controls
中删除,但迭代控件。这意味着,如果模板在这些移除线期间渲染,则 controls
数组将比 cart2
长,但 i
受到控件长度的限制,因此在索引 cart2 时可能会超出范围。
如果您不关心已删除的条目会短暂存在,则可以进行访问
cart2[i]?.name
。由于无论如何控件都将被删除,因此这应该不会显示任何内容并防止越界访问尝试。
您还可以尝试取消您正在使用的“并行数组”。
controls
数组可以转换为 FormGroups
数组,而不是 FormControl
数组,其中每个组都是一个产品,并且所有必需的信息(如 name
)都添加到内部 FormGroups
中。尽管在这样的情况下,这可能不合适,其中 name
(大概)不是表单本身的一部分。