Angular子组件@Input更新时数组push对象仅覆盖未追加问题
Angular子组件数组追加失败问题
我是Angular新手,已通过@Input装饰器将父组件的productCarted对象传递到子组件。现在希望在父组件事件触发后,将该对象追加到子组件的现有同类型对象数组中,于是使用ngOnChanges钩子监听@Input对象变化并调用push方法添加,但结果是每次仅覆盖最后一条数据,无法实现数组追加,求解决办法。
父组件代码
<div class="container-fluid"> <div class="row"> <div class="col-md-12"> <app-header (selectedFeature)="selection($event)"></app-header> </div> </div> <div class="row"> <div class="col-md-12"> <app-products *ngIf="loadedFeature ==='products'" (emitProduct)="addCart($event)"></app-products> </div> </div> <div class="row"> <div class="col-md-6"> <app-cart *ngIf="loadedFeature ==='cart'" [prod]="productCarted" (emitProd)="cart($event)"></app-cart> </div> </div> </div>
子组件代码
import { Component, Input, OnChanges} from '@angular/core'; import { products } from '../products/products.model'; @Component({ selector: 'app-cart', templateUrl: './cart.component.html', styleUrls: ['./cart.component.css'] }) export class CartComponent implements OnChanges{ @Input() prod: products; products: products[] = [ new products('LED TV', 'Good viewing experience', 450, "https://prod.citi.isolation/c/i/aHR0cHM6Ly9pbWFnZXMucGhpbGlwcy5jb20vaXMvaW1hZ2UvUGhpbGlwc0NvbnN1bWVyLzUwUFVUNjYwNF85OC1JTVMtZW5fU0c_JGpwZ2xhcmdlJCZ3aWQ9OTYw"), new products('LCD TV', 'Affordable viewing experience', 200, "https://prod.citi.isolation/c/i/aHR0cHM6Ly9pbWFnZXMucGhpbGlwcy5jb20vaXMvaW1hZ2UvUGhpbGlwc0NvbnN1bWVyLzUwUFVUNjYwNF85OC1JTVMtZW5fU0c_JGpwZ2xhcmdlJCZ3aWQ9OTYw") ]; ngOnChanges(){ const prod = new products(this.prod.name,this.prod.description,this.prod.price,this.prod.imagePath); this.products.push(prod); } }
问题原因及解决办法
核心原因
- 组件重建导致数组重置:父组件中
app-cart使用了*ngIf="loadedFeature ==='cart'",当切换到其他功能再切回购物车时,子组件会被销毁重建,products数组会重置为初始的两个元素,看起来像是“覆盖”,实际是数组被重新初始化。 - 对象引用未更新导致
ngOnChanges不触发:如果父组件每次传递的productCarted是同一个对象引用(仅修改内部属性),ngOnChanges只会在第一次接收时触发,后续事件不会触发钩子,导致无法追加新元素。
具体解决方法
方法一:避免组件重建
将*ngIf替换为[hidden],这样组件不会被销毁,数组会保留之前的内容:
<app-cart [hidden]="loadedFeature !=='cart'" [prod]="productCarted" (emitProd)="cart($event)"></app-cart>
方法二:更新对象引用触发ngOnChanges
在父组件的addCart方法中,每次创建新的对象实例,确保引用更新:
// 父组件中的addCart方法 addCart(product: products) { // 解构创建新对象,更新引用 this.productCarted = {...product}; }
方法三:父组件维护购物车数组(推荐方案)
遵循Angular单向数据流理念,由父组件维护购物车数组,子组件仅负责展示:
- 父组件修改:
<app-cart *ngIf="loadedFeature ==='cart'" [products]="cartProducts" (emitProd)="cart($event)"></app-cart>
// 父组件类定义 cartProducts: products[] = []; addCart(product: products) { // 添加新对象到数组 this.cartProducts.push({...product}); }
- 子组件修改:
import { Component, Input} from '@angular/core'; import { products } from '../products/products.model'; @Component({ selector: 'app-cart', templateUrl: './cart.component.html', styleUrls: ['./cart.component.css'] }) export class CartComponent { @Input() products: products[] = []; // 无需再使用ngOnChanges,数组更新时子组件自动感知 }
方法四:优化ngOnChanges逻辑
通过SimpleChanges参数判断prod的变化,确保仅在有效更新时添加元素:
import { Component, Input, OnChanges, SimpleChanges} from '@angular/core'; import { products } from '../products/products.model'; @Component({ selector: 'app-cart', templateUrl: './cart.component.html', styleUrls: ['./cart.component.css'] }) export class CartComponent implements OnChanges{ @Input() prod: products; products: products[] = [ new products('LED TV', 'Good viewing experience', 450, "https://prod.citi.isolation/c/i/aHR0cHM6Ly9pbWFnZXMucGhpbGlwcy5jb20vaXMvaW1hZ2UvUGhpbGlwc0NvbnN1bWVyLzUwUFVUNjYwNF85OC1JTVMtZW5fU0c_JGpwZ2xhcmdlJCZ3aWQ9OTYw"), new products('LCD TV', 'Affordable viewing experience', 200, "https://prod.citi.isolation/c/i/aHR0cHM6Ly9pbWFnZXMucGhpbGlwcy5jb20vaXMvaW1hZ2UvUGhpbGlwc0NvbnN1bWVyLzUwUFVUNjYwNF85OC1JTVMtZW5fU0c_JGpwZ2xhcmdlJCZ3aWQ9OTYw") ]; ngOnChanges(changes: SimpleChanges) { if (changes['prod'] && changes['prod'].currentValue && !changes['prod'].firstChange) { const newProd = changes['prod'].currentValue; const prod = new products(newProd.name, newProd.description, newProd.price, newProd.imagePath); this.products.push(prod); } } }
内容的提问来源于stack exchange,提问作者shahiedul
相关产品推荐
相关产品推荐

