Angular中点击子组件按钮后如何刷新父组件?
问题描述
我在弹窗(子组件)中更新食材(Ingrediant)数量,希望弹窗关闭时食材卡片所在的父组件能重新渲染并显示新数量,但不知道怎么实现。
食材服务代码
// 更新 updateAmount(id: string, newAmount: number): Observable<Ingrediant>{ return this.http.put<Ingrediant>(`${this.url}/${id}`, {amount: newAmount}); }
食材组件HTML代码
<div class="ingrediant-slider"> <hr/> <h4 class="ingrediant-heading">Bread</h4> <div class="carousel"> <img src="../../assets/arrows/left-arrow.png" class="arrow-left" (click)="scroll(-scrollAmount)"> <img src="../../assets/arrows/right-arrow.png" class="arrow-right" (click)="scroll(scrollAmount)"> <div class="card" *ngFor="let breadIngrediants of breadIngrediants; let i=index" > <div class="top-circle"> <h4>{{breadIngrediants.amount}}</h4> </div> <div class="circle"> <img [src]="breadIngrediants.image" class="card-img" alt="Image of burger"/> </div> <h3>{{breadIngrediants.name}}</h3> <button (click)="showPopup = true; selectedIngrediants = breadIngrediants">Update</button> </div> </div> </div> <app-popup *ngIf="showPopup" [selectedIngrediants]="selectedIngrediants" (close)="showPopup = false" (updated)="onUpdate()"></app-popup>
食材组件.ts代码
// 当事件触发时添加此方法以更新食材列表 onUpdate() { // 重新获取食材数据并更新本地变量 this.ingrediantService.items$.subscribe((data) => { this.breadIngrediants = data; console.log(data); this.cdr.detectChanges(); }); }
弹窗HTML代码
<div class="popup"[style.top.px]="getYPosition(selectedIngrediants)"> <div class="left-pannel"> <div class="circle"> <img [src]="selectedIngrediants.image" class="card-img" alt="Image of burger"/> </div> </div> <div class="right-pannel"> </div> <h2>{{ selectedIngrediants.name }}</h2> <p>{{ getDescription() }}</p> <h4>Amount</h4> <input type="number" matInput placeholder="0" color="accent" [value]="selectedIngrediants.amount" (change)="detectAmountChange($event)" > <button class="primary-btn" (click)="updateAmount(selectedIngrediants._id!); closePopup();">Update</button> <button class="secondary-btn" (click)="closePopup()" >Cancel</button> </div>
弹窗.ts代码
// 将newAmountPlaceholder改为当前输入值 detectAmountChange(e: any){ this.newAmountPlaceholder = +e.target.value } @Output() updated: EventEmitter<void> = new EventEmitter<void>(); updateAmount(id: string) { this.ingrediantService.updateAmount(id, this.newAmountPlaceholder).subscribe((selectedIngrediant) => { console.log(selectedIngrediant.amount); this.updated.emit(); // 更新成功时触发事件 }); }
解决方案
方法1:优化现有事件订阅逻辑
当前的实现思路没问题,但存在订阅重复创建的隐患,且需要确保服务中的items$是实时更新的数据流:
- 限制单次订阅:在
onUpdate中使用take(1)避免重复订阅导致的内存泄漏
import { take } from 'rxjs'; onUpdate() { this.ingrediantService.items$.pipe(take(1)).subscribe((data) => { this.breadIngrediants = data; }); }
- 同步更新服务数据流:如果
items$是BehaviorSubject,在服务的updateAmount方法中更新后端数据后,要同步更新items$的值,确保父组件能拿到最新数据:
// 食材服务中补充逻辑 private itemsSubject = new BehaviorSubject<Ingrediant[]>([]); items$ = this.itemsSubject.asObservable(); updateAmount(id: string, newAmount: number): Observable<Ingrediant>{ return this.http.put<Ingrediant>(`${this.url}/${id}`, {amount: newAmount}).pipe( tap(updatedItem => { // 更新本地数据流中的对应项 const currentItems = this.itemsSubject.value; const updatedItems = currentItems.map(item => item._id === id ? updatedItem : item ); this.itemsSubject.next(updatedItems); }) ); }
方法2:直接传递更新后的食材数据
无需重新拉取整个列表,弹窗更新成功后把最新数据传给父组件,父组件直接修改本地数组:
- 修改弹窗的事件类型
@Output() updated: EventEmitter<Ingrediant> = new EventEmitter<Ingrediant>();
- 更新成功时传递数据
updateAmount(id: string) { this.ingrediantService.updateAmount(id, this.newAmountPlaceholder).subscribe((updatedIngrediant) => { this.updated.emit(updatedIngrediant); this.closePopup(); }); }
- 父组件接收并更新对应项
onUpdate(updatedIngrediant: Ingrediant) { const targetIndex = this.breadIngrediants.findIndex(item => item._id === updatedIngrediant._id); if (targetIndex !== -1) { // 触发Angular变更检测 this.breadIngrediants[targetIndex] = {...this.breadIngrediants[targetIndex], ...updatedIngrediant}; } }
- 修改父组件HTML的事件绑定
<app-popup *ngIf="showPopup" [selectedIngrediants]="selectedIngrediants" (close)="showPopup = false" (updated)="onUpdate($event)"></app-popup>
方法3:状态管理工具(复杂场景适用)
如果应用规模较大,建议使用NgRx等状态管理库统一维护食材数据状态,更新操作后状态自动同步,所有依赖组件会自动刷新。
内容的提问来源于stack exchange,提问作者Alexa Pettitt
相关产品推荐
相关产品推荐

