【问题标题】:Dynamic angular form clears existing values动态角度形式清除现有值
【发布时间】:2018-06-28 01:07:00
【问题描述】:

StackBlitzExample

我正在尝试为地址集合创建一个简单的组件。用户可以添加、删除和编辑所有地址。除了存在多个地址时,这一切都有效,用户只删除第一个地址,然后添加一个新地址。新地址被添加,但现有地址也被清除。在我的应用程序中,我也收到错误 - ExpressionChangedAfterItHasBeenCheckedError。

import { Component, Input } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1><button type="button" (click)="add()">Add</button>
  <form>
  <div *ngFor="let addr of data; let i=index;">
    <input  name="{{'address1'+i}}" type="text" [(ngModel)]="addr.address1" />
    <input  name="{{'zip'+i}}" type="text" [(ngModel)]="addr.zip" />
    <button type="button" (click)="delete(i, addr)">Delete</button>
    <hr/>
  </div>
  </form>
  `,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input() name: string;
  data = [
    {
      address1:'500 Main St',
      address2:'',
      city:'Norman',
      state:'OK',
      zip:'73070'
    },
    {
      address1:'501 Main St',
      address2:'',
      city:'OKC',
      state:'OK',
      zip:'73105'
    }
  ];


  add() {
    this.data.push( { address1:'',
      address2:'',
      city:'',
      state:'',
      zip:''});
  }

  delete(index:number, row:any) {
   this.data.splice(index, 1);
  }
}

【问题讨论】:

  • 您能否更具体地说明重现此错误所需的步骤?我试过添加、编辑和删除项目,这一切似乎都适合我。
  • 我让它工作,然后停止工作。我在 getter 上得到了一些帮助,并且能够通过使用 trackBy 功能 ngFor 来修复它。

标签: angular forms dynamic


【解决方案1】:

通过使用 ngFor 的 trackBy 功能,我能够让事情正常进行。这是修改后的代码,对 StackBlitz 也进行了更正。

    @Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1><button type="button" (click)="add()">Add</button>
  <form>
  <div *ngFor="let addr of data; let i=index; trackBy:trackByIndex">
    <input  name="{{'address1'+i}}" type="text" [(ngModel)]="addr.address1" />
      <input  name="{{'address2'+i}}" type="text" [(ngModel)]="addr.address2" />
        <input  name="{{'city'+i}}" type="text" [(ngModel)]="addr.city" />
          <input  name="{{'state'+i}}" type="text" [(ngModel)]="addr.state" />
            <input  name="{{'zip'+i}}" type="text" [(ngModel)]="addr.zip" />
            <button type="button" (click)="delete(i, addr)">Delete</button>
            <hr/>
  </div>
  </form>
  `,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input() name: string;
  data = [
    {
      address1:'500 Main St',
      address2:'',
      city:'Norman',
      state:'OK',
      zip:'73070'
    },
    {
      address1:'501 Main St',
      address2:'',
      city:'OKC',
      state:'OK',
      zip:'73105'
    }
  ];


  add() {
    this.data.push( { address1:'',
      address2:'',
      city:'',
      state:'',
      zip:''});
  }

  public trackByIndex(index: number, value: number) {
    return index;
  }

  delete(index:number, row:any) {
   this.data.splice(index, 1);
  }
}

【讨论】:

    【解决方案2】:

    你想要一个FormArray。它非常适合这种事情。我已经继续并使用 Reactive Forms 重新创建了您的应用程序,以便您可以比较和对比并了解它是如何工作的。

    这是包含所有代码的工作示例的链接:https://stackblitz.com/edit/angular-eeamqq

    请注意,我将响应式表单的值添加到模板中,因此您可以看到它本质上是一个动态构建的对象。

    如果您希望我进一步扩展我在上述应用中使用的一些技术,请告诉我。

    我还将在此处链接代码,以便您无需加载应用程序即可查看它:

    模板:

      <button type="button" (click)="onAdd()">Add</button>
      <hr>
    
      <form [formGroup]="addressForm">
        <div formArrayName="addresses" 
             *ngFor="let address of addressForm.get('addresses').controls; let i = index;">
          <div [formGroupName]="i">
             <input formControlName="address1" placeholder="Address 1">
             <input formControlName="address2" placeholder="Address 2">
             <input formControlName="city" placeholder="City">
             <input formControlName="state" placeholder="State">
             <input formControlName="zip" placeholder="Zip">
             <button (click)="onDelete(i)">Delete</button>
          </div>
          <hr>
        </div>
      </form>
    

    组件类的重要位:

      constructor(private fb: FormBuilder) {}
    
      ngOnInit() {
        const addressForms = this.data.map(address => this.createAddressForm(address));
    
        this.addressForm = this.fb.group({
          addresses: this.fb.array(addressForms)
        });
      }
    
      createAddressGroup(address?: any) {
        return this.fb.group({
          address1: address ? address.address1 : '',
          address2: address ? address.address2 : '',
          city: address ? address.city : '',
          state: address ? address.state : '',
          zip: address ? address.zip : ''
        });
      }
    
      onAdd() {
        const addresses = this.addressForm.get('addresses') as FormArray;
        addresses.push(this.createAddressForm());
      }
    
      onDelete(index: number) {
        const addresses = this.addressForm.get('addresses') as FormArray;
        addresses.removeAt(index);
      }
    

    【讨论】:

    • 感谢您的示例。我们一直在尝试只用一种风格来做表单,我们选择不使用反应式表单。我能够通过使用 ngFor 的 trackBy 功能找到解决方案。
    猜你喜欢
    • 2013-10-30
    • 1970-01-01
    • 2019-10-30
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 2015-09-23
    • 2018-05-21
    • 1970-01-01
    相关资源
    最近更新 更多