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

Angular 13父子组件数据获取异常:子组件ngModel绑定后父组件数据为空

问题描述

我创建了NewInvoiceComponent与InvoiceItemListComponent两个组件,其中InvoiceItemListComponent用于处理发票项(包含count、unit、description、price字段)。已实现动态添加、删除输入字段的功能,相关按钮运行正常,但提交表单时invoiceItems数组内的项仍为null。我在InvoiceItemListComponent中使用了[(ngModel)],请问这些动态输入框能否使用ngModel?或是@Output存在问题?


代码实现

父组件(NewInvoiceComponent)

TypeScript代码

export class NewInvoiceComponent implements OnInit {
  public invoiceItems: InvoiceItem[] = [];

  constructor() { }

  ngOnInit(): void {

  }

  addInvoiceItem(): void {
    let next = 0;

    if (this.invoiceItems.length > 0) {
      next = this.invoiceItems.length;
    }
    this.invoiceItems.push({count: null, description: null, price: null, unit: null, id: next});
  }

  deleteInvoiceItem(item: InvoiceItem): void {
    this.invoiceItems = this.invoiceItems.filter(element => element.id !== item.id);
  }

  onSubmit(): void {
    console.log(this.invoiceItems);
  }
}

HTML模板

<app-invoice-item-list [invoiceItemList]="invoiceItems" (onDelete)="deleteInvoiceItem($event)"></app-invoice-item-list>
<button class="btn btn-primary" type="button" (click)="addInvoiceItem()">New item</button>
<!-- another inputs -->
<div class="col-lg-12">
<button class="btn btn-primary" type="submit">Create invoice</button>
</div>

子组件(InvoiceItemListComponent)

TypeScript代码

export class InvoiceItemListComponent implements OnInit {
  @Input() invoiceItemList = [];
  // tslint:disable-next-line:no-output-on-prefix
  @Output() onDelete = new EventEmitter<any>();
  constructor() {
    console.log(this.invoiceItemList);
  }

  ngOnInit(): void {
  }

  onDeleteInvoiceItem(invoiceItem) {
    console.log(invoiceItem);
    this.onDelete.emit(invoiceItem);
  }

}

HTML模板

<div class="row" *ngFor="let invoice of invoiceItemList">
  <div class="col-md-2">
    <div class="form-group">
      <label class="form-control-label" for="input-count">Count</label>
      <input id="input-count" name="count"  class="form-control form-control-alternative" [(ngModel)]="invoice.count" type="number">
    </div>
  </div>

  <div class="col-md-2">
    <div class="form-group">
      <label class="form-control-label" for="input-type">Unit</label>
      <input id="input-type" name="type"  class="form-control form-control-alternative" type="text" placeholder="ks, hod" [(ngModel)]="invoice.unit">
    </div>
  </div>

  <div class="col-md-4">
    <div class="form-group">
      <label class="form-control-label" for="input-description">Description</label>
      <input id="input-description" name="description"  class="form-control form-control-alternative" placeholder="Popis položky" type="text" [(ngModel)]="invoice.description">
    </div>
  </div>

  <div class="col-md-2">
    <div class="form-group">
      <label class="form-control-label" for="input-item-price">Price</label>
      <input id="input-item-price" name="address"  class="form-control form-control-alternative" placeholder="Cena" type="text" [(ngModel)]="invoice.price">
    </div>
  </div>

  <div class="col-md-2">
    <div class="form-group">
      <button class="btn btn-danger" type="button" (click)="onDeleteInvoiceItem(invoice)">Delete</button>
    </div>
  </div>

</div>

问题分析与解决方案
  1. 动态输入框完全可以使用[(ngModel)],你的问题既不是ngModel的使用限制,也不是@Output的问题——删除功能正常说明@Output的实现是正确的。

  2. 核心问题:ngModel未正确绑定
    当[(ngModel)]没有包裹在<form>标签内时,Angular默认会将其视为表单控件的一部分,此时必须添加[ngModelOptions]="{standalone: true}"来告诉Angular该输入框是独立的,否则双向绑定无法生效。

  3. 修改方案
    在子组件的所有[(ngModel)]绑定的输入框上添加[ngModelOptions]="{standalone: true}",示例如下:

    <input id="input-count" name="count" class="form-control form-control-alternative" 
           [(ngModel)]="invoice.count" type="number" 
           [ngModelOptions]="{standalone: true}">
    

    对所有四个输入框执行相同修改即可。

  4. 额外优化建议

    • 给子组件的@Input指定明确类型:@Input() invoiceItemList: InvoiceItem[] = [];,保持类型一致性,避免潜在错误。
    • 父组件模板中的提交按钮建议包裹在<form>标签内(并添加(ngSubmit)="onSubmit()"),这样更符合Angular表单的规范,也可以省去standalone配置:
      <form (ngSubmit)="onSubmit()">
        <app-invoice-item-list [invoiceItemList]="invoiceItems" (onDelete)="deleteInvoiceItem($event)"></app-invoice-item-list>
        <button class="btn btn-primary" type="button" (click)="addInvoiceItem()">New item</button>
        <!-- another inputs -->
        <div class="col-lg-12">
          <button class="btn btn-primary" type="submit">Create invoice</button>
        </div>
      </form>
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:27:22