由浅入深理解动态表单的一般使用

当表单结构类似,频繁地使用响应式表单或许是一件增加工作量地事情,除了将模板进行合理地封装,表单模型也要能够灵活地构造,此时推荐使用动态表单。

先理解再优化

动态表单模板中,value、label均动态化,表单字段也是动态绑定,比较基础地模型是一个数组循环与模板绑定处理;生成一个formGroup,会根据不同地类型区分,此时不包含重复项。
数据模型数据:

this.base = [
      {
        key: 'userName',
        label: '姓名',
        value: null,
        validators: [Validators.required]
      },
      {
        key: 'age',
        label: '年龄',
        value: null,
        validators: [Validators.required]
      }
    ];

form生成:

this.form = this.toFormGroup(this.base);
toFormGroup(options: any[]) {
    const group = {};
    options.forEach(item => {
      group[item.key] = new FormControl(item.value, item.validators);
    });
    return new FormGroup(group);
  }

模板

<form nz-form [formGroup]="form" (ngSubmit)="submit(form)">
    <div *ngFor="let item of base">
      <ng-container [formGroup]="form">
        <div nz-row nzFlex [nzGutter]="8">
          <div nz-col [nzSpan]="6">
            <nz-form-item>
              <nz-form-label [nzSpan]="10">{{item.label}}</nz-form-label>
              <nz-form-control [nzSpan]="14">
                <input nz-input type="text" [formControlName]="item.key" placeholder="Enter Your Working date..." />
              </nz-form-control>
            </nz-form-item>
          </div>
        </div>
      </ng-container>
    </div>
   </form>

image.png

优化

模板组件化,方法服务化
basic-form

<form nz-form [formGroup]="form" (ngSubmit)="submit(form)">
  <ng-container [formGroup]="form">
    <div nz-row nzFlex [nzGutter]="8">
      <div nz-col [nzSpan]="6" *ngFor="let item of base">
        <nz-form-item>
          <nz-form-label [nzSpan]="10">{{item.label}}</nz-form-label>
          <nz-form-control [nzSpan]="14">
            <input nz-input type="text" [formControlName]="item.key" placeholder="{{item.placeholder}}" />
          </nz-form-control>
        </nz-form-item>
      </div>
    </div>
  </ng-container>
</form>

我们需要实现一个根据不同学龄阶段的学生生成不同的某个申请表单,这时表单需要动态化处理,
修改代码:
view.component.html

<div nz-row nzGutter="16">
  <div nz-col nzSpan="24">
    <nz-radio-group [(ngModel)]="grade" (ngModelChange)="gradeChange($event)">
      <label nz-radio-button nzValue="junior"><span>小学</span></label>
      <label nz-radio-button nzValue="middle"><span>初中</span></label>
      <label nz-radio-button nzValue="high"><span>高中</span></label>
    </nz-radio-group>
  </div>
</div>
<section class="form-container">
  <basic-form [form]="form" [data]="formData"></basic-form>
</section>
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormArray, FormControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { FormService } from '../share/form.service';
interface FormFieldObject {
  key: string;
  label: string;
  value: any;
  placeholder: string;
  validators: ValidatorFn[];
}
@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrls: ['./view.component.scss']
})

export class ViewComponent implements OnInit, AfterViewInit {

  constructor(
    private formService: FormService
  ) { }
  form: FormGroup;
  formData: FormFieldObject[];
  base: FormFieldObject[];
  grade = 'junior';
  ngOnInit() {
    this.base = [
      {
        key: 'userName',
        label: '姓名',
        value: null,
        placeholder: 'Enter Your Name',
        validators: [Validators.required]
      },
      {
        key: 'age',
        label: '年龄',
        value: null,
        placeholder: 'Enter Your Age',
        validators: [Validators.required]
      }
    ];
    this.formData = [...this.base];
    this.form = this.formService.createForm(this.formData);
  }
  gradeChange(event) {
    this.base = [
      {
        key: 'userName',
        label: '姓名',
        value: null,
        placeholder: 'Enter Your Name',
        validators: [Validators.required]
      },
      {
        key: 'age',
        label: '年龄',
        value: null,
        placeholder: 'Enter Your Age',
        validators: [Validators.required]
      }
    ];
    if (event === 'middle') {
      const pre = [
        {
          key: 'junior',
          label: '小学教育',
          value: null,
          placeholder: 'Enter Your junior school',
          validators: [Validators.required]
        }
      ];
      this.formData = [...this.base, ...pre];
      this.form = this.formService.createForm(this.formData);
    } else if (event === 'junior') {
      this.formData = [...this.base];
      this.form = this.formService.createForm(this.formData);
    } else {
      const pre = [
        {
          key: 'junior',
          label: '小学教育',
          value: null,
          placeholder: 'Enter Your junior school',
          validators: [Validators.required]
        },
        {
          key: 'middle',
          label: '初中教育',
          value: null,
          placeholder: 'Enter Your middle school',
          validators: [Validators.required]
        }
      ];
      this.formData = [...this.base, ...pre];
      this.form = this.formService.createForm(this.formData);
    }
  }
  ngAfterViewInit() {

  }


}
import { Injectable } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';

@Injectable({
  providedIn: 'root'
})
export class FormService {

  constructor() { }
  createForm(arrays: any[]) {
    const group = {};
    arrays.forEach(item => {
      group[item.key] = new FormControl(item.value, item.validators);
    });
    return new FormGroup(group);
  }
}

模板组件

import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
  // tslint:disable-next-line: component-selector
  selector: 'basic-form',
  templateUrl: './basic-form.component.html',
  styleUrls: ['./basic-form.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class BasicFormComponent implements OnInit {

  @Input() form: FormGroup;
  @Input() data: any[];
  constructor() { }

  ngOnInit() {
  }
  submit() {
    console.log(this.form.valid);
   }

}

image.png

将表单控件的value、字段、placeholder文本,以及简单的验证器均动态化,保证了多条件下均可以提交和验证表单。


何弃疗
106 声望7 粉丝

前端路上摸爬滚打;野路子前端debug