一、定义表单控件基类

// base-form-control.ts
// 控件接口,这里定义表单控件可能用到的属性
interface Control {
    value: any;
    label: string;
    key: string;
    controlType: string;
    placeholder: string;
    required: boolean; 
    options: Array<{label: string; value: string}>;
}
type PartialControl = Partial<Control>		// 转为可选属性

export class BaseFormControl {
    value: any;
    label: string;
    key: string;
    controlType: string;
    placeholder: string;
    required: boolean; 
    options: Array<{label: string; value: string}>;
    
    constructor(options: PartialControl = {}) {
        this.value = options.value || null;
        this.label = options.label || '';
        this.key = options.key || '';
        this.controlType = options.controlType || 'text';
        this.required = !!options.required;
        this.options = options.options || [];
    }
}

二、定义动态表单控件组件

我们在这个组件定义可能用到的表单控件,比如文本框text、下拉框select、文本域textarea以及其他控件或者第三方表单控件等。

<!-- dynamic-control.component.html -->
<div [formGroup]="form">
    <label [for]="control.key">{{control.label}}</label>
    <ng-container [ngSwitch]="control.controlType">
        <ng-container *ngSwitchCase="'text'">
            <input type="text" [formControlName]="control.key" [id]="control.key" [placeholder]="control.placeholder">
        </ng-container>
        <ng-container *ngSwitchCase="'select'">
           <select [name]="control.label" [id]="control.key" [formControlName]="control.key">
                <option style="color: #ccc;" *ngIf="control.placeholder" disabled selected>{{control.placeholder}}</option>
                <option *ngFor="let item of control.options" [value]="item.value">{{item.label}}</option>
           </select>
        </ng-container>
        <ng-container *ngSwitchCase="'textarea'">
           <textarea style="vertical-align: top;" [formControlName]="control.key" [name]="control.label" [id]="control.key" cols="30" rows="10" [placeholder]="control.placeholder"></textarea>
        </ng-container>
    </ng-container>
</div>
// dynamic-control.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { BaseFormControl } from '../base-form-control';

@Component({
  selector: 'app-dynamic-control',
  templateUrl: './dynamic-control.component.html',
  styleUrls: ['./dynamic-control.component.less']
})
export class DynamicControlComponent implements OnInit {
  @Input() form: FormGroup;
  @Input() control: BaseFormControl;
  constructor() { }

  ngOnInit(): void {
  }

}

三、定义动态表单组件

<!-- dynamic-form.component.html -->
<div>
    <form (ngSubmit)="onSubmit()" [formGroup]="form">
      <div *ngFor="let control of controls">
        <app-dynamic-control [control]="control" [form]="form"></app-dynamic-control>
      </div>
    </form>
  
    <div>表单数据:{{form.getRawValue() | json}}</div>
</div>
// dynamic-form.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { BaseFormControl } from '../base-form-control';
@Component({
  selector: 'app-dynamic-form',
  templateUrl: './dynamic-form.component.html',
  styleUrls: ['./dynamic-form.component.less']
})
export class DynamicFormComponent implements OnInit {
  form: FormGroup;
  @Input() controls: BaseFormControl[];
  constructor() { }


  ngOnInit(): void {
    this.form = this.toFormGroup(this.controls);
  }

  toFormGroup(controls: BaseFormControl[] ) {
    const group: any = {};
    controls.forEach(control => {
      group[control.key] = control.required ? new FormControl(control.value, Validators.required) : new FormControl(control.value);
    });
    return new FormGroup(group);
  }
  onSubmit() {}

}

四、使用动态表单组件

<h3>动态表单</h3>

<app-dynamic-form [controls]="controls"></app-dynamic-form>
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-car',
  templateUrl: './car.component.html',
  styleUrls: ['./car.component.less']
})
export class CarComponent implements OnInit {
    controls = [
    {
      label: '姓名',
      value: '',
      key: 'name',
      controlType: 'text',
      placeholder: '请输入姓名'
    },
    {
      label: '爱好',
      value: '',
      key: 'hobby',
      controlType: 'select',
      placeholder: '请选择爱好',
      options: [
        {
          label: '足球',
          value: 1
        },
        {
          label: '篮球',
          value: 2
        },
        {
          label: '游泳',
          value: 3
        }
      ]
    },
    {
      label: '个人简介',
      value: '',
      key: 'detail',
      controlType: 'textarea',
      placeholder: '请输入个人简介'
    },
  ]
  constructor() { }

  ngOnInit(): void {
  }

}

在这里插入图片描述