导入所需模块:
ReactiveFormsModule
DynamicFormComponent.html
<div [formGroup]="form"> <label [attr.for]="formItem.key">{{formItem.label}}</label> <div [ngSwitch]="formItem.controlType"> <input *ngSwitchCase="'textbox'" [formControlName]="formItem.key" [id]="formItem.key" [type]="formItem.type"> <select [id]="formItem.key" *ngSwitchCase="'dropdown'" [formControlName]="formItem.key"> <option *ngFor="let opt of formItem.options" [value]="opt.key">{{opt.value}}</option> </select> </div> <div class="errorMessage" *ngIf="!isValid">{{formItem.label}} is required</div> </div>
DynamicFormComponent.ts
import {Component, Input, OnInit} from '@angular/core'; import {FormItemBase} from './form-item-base'; import {FormGroup} from '@angular/forms'; @Component({ selector: 'app-dynamic-form', templateUrl: './dynamic-form.component.html', styleUrls: ['./dynamic-form.component.css'] }) export class DynamicFormComponent implements OnInit { @Input() formItem: FormItemBase<any>; @Input() form: FormGroup; constructor() { } ngOnInit() { } get isValid() { return this.form.controls[this.formItem.key].valid; } }
FormItemBase.ts
export class FormItemBase<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 || ''; } }
FormTextbox.ts
import {FormItemBase} from './form-item-base'; export class FormTextbox extends FormItemBase<string> { controlType = 'textbox'; type: string; constructor(options: {} = {}) { super(options); this.type = options['type'] || ''; } }
FormDropdown.ts
import {FormItemBase} from './form-item-base'; export class FormDropdown extends FormItemBase<string> { controlType = 'dropdown'; options: {key: string, value: string}[] = []; constructor(options: {} = {}) { super(options); this.options = options['options'] || []; } }
FormItemControl.ts
import {Injectable} from '@angular/core'; import {FormItemBase} from './form-item-base'; import {FormControl, FormGroup, Validators} from '@angular/forms'; @Injectable() export class FormItemControlService { constructor() { } toFormGroup(formItems: FormItemBase<any>[]) { const group: any = {}; formItems.forEach(formItem => { group[formItem.key] = formItem.required ? new FormControl(formItem.value || '', Validators.required) : new FormControl(formItem.value || ''); }); return new FormGroup(group); } }
QuestionComponent.html
<div class="container"> <app-question-form [questions]="questions"></app-question-form> </div>
QuestionComponent.ts
import { Component, OnInit } from '@angular/core'; import {QuestionFromService} from './question-form/question-form.service'; @Component({ selector: 'app-question', templateUrl: './question.component.html', styleUrls: ['./question.component.css'] }) export class QuestionComponent implements OnInit { questions: any[]; constructor(questionFormService: QuestionFromService) { this.questions = questionFormService.getQuestionFormItems(); } ngOnInit() { } }
QuestionFormComponent.html
<div> <form (ngSubmit)="onSubmit()" [formGroup]="form"> <div *ngFor="let question of questions" class="form-row"> <app-dynamic-form [formItem]="question" [form]="form"></app-dynamic-form> </div> <div class="form-row"> <button type="submit" [disabled]="!form.valid">Save</button> </div> </form> <div *ngIf="payLoad" class="form-row"> <strong>Saved the following values</strong><br>{{payLoad}} </div> </div>
QuestionFormComponent.ts
import {Component, Input, OnInit} from '@angular/core'; import {FormGroup} from '@angular/forms'; import {FormItemBase} from '../../common/component/dynamic-form/form-item-base'; import {FormItemControlService} from '../../common/component/dynamic-form/form-item-control.service'; @Component({ selector: 'app-question-form', templateUrl: './question-form.component.html', styleUrls: ['./question-form.component.css'] }) export class QuestionFormComponent implements OnInit { form: FormGroup; payLoad = ''; @Input() questions: FormItemBase<any>[] = []; constructor(private fromItemControlService: FormItemControlService) { } ngOnInit() { this.form = this.fromItemControlService.toFormGroup(this.questions); } onSubmit() { this.payLoad = JSON.stringify(this.form.value); } }
QuestionForm.service.ts
import {Injectable} from '@angular/core'; import {FormItemBase} from '../../common/component/dynamic-form/form-item-base'; import {FormDropdown} from '../../common/component/dynamic-form/form-dropdown'; import {FormTextbox} from '../../common/component/dynamic-form/form-textbox'; @Injectable() export class QuestionFromService { getQuestionFormItems() { const questionFormItems: FormItemBase<any>[] = [ new FormDropdown({ 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 FormTextbox({ key: 'firstName', label: 'First name', value: 'Bombasto', required: true, order: 1 }), new FormTextbox({ key: 'emailAddress', label: 'Email', type: 'email', required: false, order: 2 }) ]; return questionFormItems.sort((a, b) => a.order - b.order); } }