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

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$是实时更新的数据流:

  1. 限制单次订阅:在onUpdate中使用take(1)避免重复订阅导致的内存泄漏
import { take } from 'rxjs';

onUpdate() {
  this.ingrediantService.items$.pipe(take(1)).subscribe((data) => {
    this.breadIngrediants = data;
  });
}
  1. 同步更新服务数据流:如果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:直接传递更新后的食材数据

无需重新拉取整个列表,弹窗更新成功后把最新数据传给父组件,父组件直接修改本地数组:

  1. 修改弹窗的事件类型
@Output() updated: EventEmitter<Ingrediant> = new EventEmitter<Ingrediant>();
  1. 更新成功时传递数据
updateAmount(id: string) {
  this.ingrediantService.updateAmount(id, this.newAmountPlaceholder).subscribe((updatedIngrediant) => {
    this.updated.emit(updatedIngrediant);
    this.closePopup();
  });
}
  1. 父组件接收并更新对应项
onUpdate(updatedIngrediant: Ingrediant) {
  const targetIndex = this.breadIngrediants.findIndex(item => item._id === updatedIngrediant._id);
  if (targetIndex !== -1) {
    // 触发Angular变更检测
    this.breadIngrediants[targetIndex] = {...this.breadIngrediants[targetIndex], ...updatedIngrediant};
  }
}
  1. 修改父组件HTML的事件绑定
<app-popup *ngIf="showPopup" [selectedIngrediants]="selectedIngrediants" (close)="showPopup = false" (updated)="onUpdate($event)"></app-popup>

方法3:状态管理工具(复杂场景适用)

如果应用规模较大,建议使用NgRx等状态管理库统一维护食材数据状态,更新操作后状态自动同步,所有依赖组件会自动刷新。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:58:13