html 响应式表单:使用FormArray

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了html 响应式表单:使用FormArray相关的知识,希望对你有一定的参考价值。

import { Component, Input, OnChanges }       from '@angular/core';
import { FormArray, FormBuilder, FormGroup } from '@angular/forms';

import { Address, Hero, states } from './data-model';
import { HeroService }           from './hero.service';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html'
})
export class HeroDetailComponent implements OnChanges {
  @Input() hero: Hero;

  heroForm: FormGroup;
  nameChangeLog: string[] = [];
  states = states;

  constructor(
    private fb: FormBuilder,
    private heroService: HeroService) {

    this.createForm();
    this.logNameChange();
  }

  createForm() {
    this.heroForm = this.fb.group({
      name: '',
      secretLairs: this.fb.array([]),
      power: '',
      sidekick: ''
    });
  }

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

  get secretLairs(): FormArray {
    return this.heroForm.get('secretLairs') as FormArray;
  };

  setAddresses(addresses: Address[]) {
    const addressFGs = addresses.map(address => this.fb.group(address));
    
    // formArray里面填的值是FormGroup数组,使用时候其formGroupName就是数组index值
    const addressFormArray = this.fb.array(addressFGs); 
    this.heroForm.setControl('secretLairs', addressFormArray); // 重新设置一个formArray
  }

  addLair() {
    this.secretLairs.push(this.fb.group(new Address()));
  }

  onSubmit() {
    this.hero = this.prepareSaveHero();
    this.heroService.updateHero(this.hero).subscribe(/* error handling */);
    this.ngOnChanges();
  }

  prepareSaveHero(): Hero {
    const formModel = this.heroForm.value;

    // deep copy of form model lairs
    const secretLairsDeepCopy: Address[] = formModel.secretLairs.map(
      (address: Address) => Object.assign({}, address)
    );

    // return new `Hero` object containing a combination of original hero value(s)
    // and deep copies of changed form model values
    const saveHero: Hero = {
      id: this.hero.id,
      name: formModel.name as string,
      // addresses: formModel.secretLairs // <-- bad!
      addresses: secretLairsDeepCopy
    };
    return saveHero;
  }

  revert() { this.ngOnChanges(); }

  logNameChange() {
    const nameControl = this.heroForm.get('name');
    nameControl.valueChanges.forEach(
      (value: string) => this.nameChangeLog.push(value)
    );
  }
}
<form [formGroup]="heroForm" (ngSubmit)="onSubmit()" novalidate>
  <div style="margin-bottom: 1em">
    <button type="submit"
            [disabled]="heroForm.pristine" class="btn btn-success">Save</button> &nbsp;
    <button type="reset" (click)="revert()"
            [disabled]="heroForm.pristine" class="btn btn-danger">Revert</button>
  </div>

  <!-- Hero Detail Controls -->
  <div class="form-group">
      <label class="center-block">Name:
        <input class="form-control" formControlName="name">
      </label>
  </div>

  <div formArrayName="secretLairs" class="well well-lg">
    <div *ngFor="let address of 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>
    <button (click)="addLair()" type="button">Add a Secret Lair</button>
  </div>
  <div class="form-group radio">
    <h4>Super power:</h4>
    <label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
    <label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
    <label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
  </div>
  <div class="checkbox">
    <label class="center-block">
      <input type="checkbox" formControlName="sidekick">I have a sidekick.
    </label>
  </div>
</form>

<p>heroForm value: {{ heroForm.value | json}}</p>

<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>

以上是关于html 响应式表单:使用FormArray的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 动态生成响应式表单

Angular 动态增减表单项

如何创建您的第一个 Angular Reactive Form

html 响应式表单:使用FormBuilder

FormArray 字段的角度自定义验证(反应式表单)

formArray 中的可拖动 formGroups(反应式表单)