使用ng new async-form建立一個新工程,在app.module.ts中引入ReactiveFormsModule模塊並在根模塊中導入html
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ ReactiveFormsModule ] })
export class QuestionBase<T> { value: T;//表單元素的值 key: string;//表單元素鍵的名稱 label: string;//輸入元素的標題 required: boolean;//是否必輸 order: number;//排序 controlType: string;//表單的類型 選擇框/文本輸入框 constructor(options: { value?: T, key?: string, label?: string, required?: boolean, order?: number, controlType?: string } = {}) { this.value = options.value; this.key = options.key || ''; this.label = options.label || ''; this.required = !!options.required; this.order = options.order === undefined ? 1 : options.order; this.controlType = options.controlType || ''; } }
選擇框元素的數據類型繼承基類,設置了controlType 爲'dropdown'並新增了屬性options數組數組
import { QuestionBase } from './question-base'; export class QuestionDropdown extends QuestionBase<string>{ controlType = "dropdown"; options: { key: string, value: string }[] = []; constructor(options: {} = {}) { super(options); this.options = options["options"] || []; } }
文本輸入框元素的數據類型繼承了基類,設置了controlType 爲'textbox',新增了type屬性,定義input的類型app
import { QuestionBase } from './question-base'; export class QuestionTextbox extends QuestionBase<string> { controlType = "textbox"; type:string; constructor(options:{} ={}){ super(options); this.type = options["type"]||"" } }
根據表單元素的派生類生成表單的數據。能夠引入一個服務類,提供表單數據。less
getQuestions(){ let questions:QuestionBase<any>[]=[ new QuestionDropdown({ key:'brave', label:'Bravery Rating', options:[ {key:'solid',value:'Solid'}, {key:'great',value:'Great'}, {key:'good',value:'Good'}, {key:'unproven',value:'Unproven'} ], order:3 }), new QuestionTextbox({ key:'firstName', label:'First name', value:"Bombasto", required:true, order:1 }), new QuestionTextbox({ key:'emailAddress', label:"Email", type:'email', order:2 }) ]; return questions.sort((a, b) => a.order - b.order); }
能夠專門提供一個服務類,將表單的數據轉成FormControl類型async
toFormGroup(questions: QuestionBase<any>[]) { let group: any = {}; questions.forEach(question => { group[question.key] = question.required?new FormControl(question.value||"",Validators.required) :new FormControl(question.value||""); }); return new FormGroup(group); }
到這裏就已經完整構建出一組FormControl 實例了。ui
<div [formGroup]="form"> <label [attr.for]="question.key">{{question.label}}</label> <div [ngSwitch]="question.controlType"> <input *ngSwitchCase="'textbox'" [formControlName]= "question.key" [id]="question.key" [type]="question.type"> <select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key"> <option *ngFor="let opt of question.options" [value]="opt.key"> {{opt.value}} </option> </select> </div> <div class="errorMessage" *ngIf="!isValid"> {{question.label}} is required </div> </div>
經過formGroup指令綁定表單數據,ngSwitch指令來選擇生成的模板,formControlName指令綁定對應的表單數據的key值this
import { Component, OnInit, Input } from '@angular/core'; import {FormGroup} from '@angular/forms'; import {QuestionBase} from '../question-base'; @Component({ selector: 'app-dynamic-form-question', templateUrl: './dynamic-form-question.component.html', styleUrls: ['./dynamic-form-question.component.less'] }) export class DynamicFormQuestionComponent implements OnInit { @Input() question:QuestionBase<any>; @Input() form :FormGroup; get isValid(){ return this.form.controls[this.question.key].valid; } constructor() { } ngOnInit() { } }
表單組件須要兩個輸入,form和question,form來獲取對應表單的鍵值是否校驗成功,question來渲染對應表單輸入元素。使用app-dynamic-form-question標籤來使用組件code
<div *ngFor="let question of questions" class="form-row"> <app-dynamic-form-question [question]="question" [form]="form"></app-dynamic-form-question> </div>
獲取到questions數據後,經過*ngFor指令來渲染單個表單組件。component
到這裏就完成了動態建立表單的功能,以這種方式來建立表單,咱們只須要開始時構建出指定的單個輸入框或者其餘表單元素的樣式以後,經過改變數據來控制表單的內容,便於後期維護。orm