首页 文章

具有嵌套表单数组的角度反应表单

提问于
浏览
17

我是Angular 2的新手,并决定学习最好的方法是通过Angular官方指南 .

我浏览了反应表格指南https://angular.io/guide/reactive-forms

演示链接:https://stackblitz.com/angular/jammvmbrpxle

虽然内容总体来说非常好,但我仍然坚持如何实现更复杂的表单 . 在给定的示例中,每个Hero都有可能存在许多地址 . 地址本身就是一个扁平的对象 .

如果地址有其他信息,例如位于地址的房间的颜色和类型,该怎么办?

export class Address {
    street = '';
    city   = '';
    state  = '';
    zip    = '';
    rooms = Room[];
}

export class Room {
     type = '';
}

这样表单模型看起来像这样......

createForm() {
this.heroForm = this.fb.group({
  name: '',
  secretLairs: this.fb.array([
      this.fb.group({
          street: '',
          city: '',
          state: '',
          zip: '',
          rooms: this.fb.array([
              this.fb.group({
                 type: ''
          })]),
      })]),
  power: '',
  sidekick: ''
});

}

EDIT - Finalized Code that works with ngOnChanges

英雄detail.component.ts

createForm() {
    this.heroForm = this.fb.group({
      name: '',
      secretLairs: this.fb.array([
        this.fb.group({
          street: '',
          city: '',
          state: '',
          zip: '',
          rooms: this.fb.array([
            this.fb.group({
              type: ''
            })
          ])
        })
      ]),
      power: '',
      sidekick: ''
    });
  }

  ngOnChanges() {
    this.heroForm.reset({
      name: this.hero.name,
    });
    this.setAddresses(this.hero.addresses);
  }

  setAddresses(addresses: Address[]) {
    let control = this.fb.array([]);
    addresses.forEach(x => {
      control.push(this.fb.group({
        street: x.street,
        city: x.city,
        state: x.state,
        zip: x.zip,
        rooms: this.setRooms(x) }))
    })
    this.heroForm.setControl('secretLairs', control);
  }

  setRooms(x) {
    let arr = new FormArray([])
    x.rooms.forEach(y => {
      arr.push(this.fb.group({ 
        type: y.type 
      }))
    })
    return arr;
  }

hero-detail.component.html(嵌套表单数组部分)

<div formArrayName="secretLairs" class="well well-lg">
  <div *ngFor="let address of heroForm.get('secretLairs').controls; let i=index" [formGroupName]="i" >
    <!-- The repeated address template -->
    <h4>Address #{{i + 1}}</h4>
    <div style="margin-left: 1em;">
      <div class="form-group">
        <label class="center-block">Street:
          <input class="form-control" formControlName="street">
        </label>
      </div>
      <div class="form-group">
        <label class="center-block">City:
          <input class="form-control" formControlName="city">
        </label>
      </div>
      <div class="form-group">
        <label class="center-block">State:
          <select class="form-control" formControlName="state">
            <option *ngFor="let state of states" [value]="state">{{state}}</option>
          </select>
        </label>
      </div>
      <div class="form-group">
        <label class="center-block">Zip Code:
          <input class="form-control" formControlName="zip">
        </label>
      </div>
    </div>
    <br>
    <!-- End of the repeated address template -->
    <div formArrayName="rooms" class="well well-lg">
      <div *ngFor="let room of address.get('rooms').controls; let j=index" [formGroupName]="j" >
          <h4>Room #{{j + 1}}</h4>
          <div class="form-group">
            <label class="center-block">Type:
              <input class="form-control" formControlName="type">
            </label>
          </div>
      </div>
    </div>
  </div>
  <button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>

1 回答

  • 49

    拥有嵌套的formarray并没有太大的不同 . 基本上你只需复制你拥有的代码......使用嵌套数组:)所以这是一个示例:

    myForm: FormGroup;
    
    constructor(private fb: FormBuilder) {
      this.myForm = this.fb.group({
        // you can also set initial formgroup inside if you like
        companies: this.fb.array([])
      })
    }
    
    addNewCompany() {
      let control = <FormArray>this.myForm.controls.companies;
      control.push(
        this.fb.group({
          company: [''],
          // nested form array, you could also add a form group initially
          projects: this.fb.array([])
        })
      )
    }
    
    deleteCompany(index) {
      let control = <FormArray>this.myForm.controls.companies;
      control.removeAt(index)
    }
    

    这就是最外层表单数组的添加和删除,因此向嵌套表单数组添加和删除表单组只是复制代码 . 从模板中我们将当前表单组传递给您要添加的数组(在本例中)为新项目/删除项目 .

    addNewProject(control) {
      control.push(
        this.fb.group({
          projectName: ['']
      }))
    }
    
    deleteProject(control, index) {
      control.removeAt(index)
    }
    

    和模板以相同的方式,你迭代你的外部formarray,然后在里面迭代你的内部表单数组:

    <form [formGroup]="myForm">
      <div formArrayName="companies">
        <div *ngFor="let comp of myForm.get('companies').controls; let i=index">
        <h3>COMPANY {{i+1}}: </h3>
        <div [formGroupName]="i">
          <input formControlName="company" />
          <button (click)="deleteCompany(i)">
             Delete Company
          </button>
          <div formArrayName="projects">
            <div *ngFor="let project of comp.get('projects').controls; let j=index">
              <h4>PROJECT {{j+1}}</h4>
              <div [formGroupName]="j">
                <input formControlName="projectName" />
                <button (click)="deleteProject(comp.controls.projects, j)">
                  Delete Project
                </button>
              </div>
            </div>
            <button (click)="addNewProject(comp.controls.projects)">
              Add new Project
            </button>
          </div>
        </div>
      </div>
    </div>
    

    DEMO

    编辑:

    要在拥有数据后为表单设置值,可以调用以下方法来迭代数据并将值设置为表单 . 在这种情况下 data 看起来像:

    data = {
      companies: [
        {
          company: "example comany",
          projects: [
            {
              projectName: "example project",
            }
          ]
        }
      ]
    }
    

    我们调用 setCompanies 将值设置为我们的表单:

    setCompanies() {
      let control = <FormArray>this.myForm.controls.companies;
      this.data.companies.forEach(x => {
        control.push(this.fb.group({ 
          company: x.company, 
          projects: this.setProjects(x) }))
      })
    }
    
    setProjects(x) {
      let arr = new FormArray([])
      x.projects.forEach(y => {
        arr.push(this.fb.group({ 
          projectName: y.projectName 
        }))
      })
      return arr;
    }
    

相关问题