Angular dynamic form (linked and displayed according to the selection)
First of all
Record it just completed a feature
Again demonstrated the parent after demand is made according to a fixed hierarchical structure dynamic interaction on the Internet to find a lot of tutorials dynamic form, the form is generated mostly at the beginning of loading. And my needs are required in the choice of the parent options under
Gangster reference Cultivation of the road and generate a form dynamically thanks ~
achieve
preparation stage
Known good configuration hierarchy
const itemConfig = [{ 'key': 'tr069', 'type': 'parent',// parent =>含有子级 item=>最底层级 'item_type': 'select',// 本层级的类型 parent 默认为select 'children': [ { 'key': 'url', 'type': 'item', 'item_type': 'input', 'value': '' }, { 'key': 'username', 'type': 'item', 'item_type': 'input', 'value': '' }, { 'key': 'password', 'type': 'item', 'item_type': 'input', 'value': '' }, { 'key': 'data', 'type': 'item', 'item_type': 'object', 'value': { 'key': '', 'value': '' } } ] },{ 'key': 'gateway', 'type': 'parent', 'item_type': 'select', 'children': [ { 'key': 'gw', 'type': 'item', 'item_type': 'input', 'value': '' } ] },{ 'key': 'optimy', 'type': 'parent', 'item_type': 'select', 'children': [ { 'key': 'enable', 'type': 'item', 'item_type': 'select', 'value': [true, false] } ] }, ];
Creating the initial level of the page
Binding change event on the initial form Options
<form autocomplete="off" [formGroup]="itemForm" fxLayout="column"> <div fxLayout="row" fxLayoutAlign="center center"> <mat-label>Group:</mat-label> <mat-form-field appearance="outline"> <mat-select formControlName="group" (selectionChange)="changeSelect($event.value,'group')"> <mat-option *ngFor="let item of itemConfig" [value]="item"> {{item.key}} </mat-option> </mat-select> </mat-form-field> </div> </form>
The initial configuration options page form
itemForm: FormGroup; // 根据父级的选择 展示的item列表 itemPushDom = []; ngOnInit(): void { this.itemForm = this.createFrom(); } createFrom(): any { const group = this._formBuilder.group({ 'group': this._formBuilder.control('') }); return group; }
Dynamic insertion
By now before operating on our pages you have the option to be able to see the initial
Then there is the dynamic insertion, in fact, is simply divided into two steps: Dom insert options and add items FormGroup
Clear previous selection plus the change after the parent
Dom Insert Options
You need to meet before the initial event delivery option is bound to change children's information
The html also need to configure the relevant type may occur through ngSwtech display (small type in this case, only select and input type if more can refer to the official documentation of the dynamic form by controlling the type of component that appears)
FormGroup Add Item
Add and delete FormGroup form item by addControl () / removeControl () (you can also add validation)
The following directly on the code
component.html (paragraph form on the inside)
<div fxLayout="row" fxLayoutAlign="center center" *ngFor="let newItem of itemPushDom"> <mat-label >{{newItem.name}}:</mat-label> <mat-form-field appearance="outline" [ngSwitch]="newItem.type"> <mat-select *ngSwitchCase="'select'" formControlName="{{newItem.name}}" (selectionChange)="changeSelect($event.value,newItem.name)" required> <mat-option *ngFor="let options of newItem.options" [value]="options.value"> {{options.key}} </mat-option> </mat-select> <input matInput *ngSwitchCase="'input'" formControlName="{{newItem.name}}" [value]="newItem.value" required> </mat-form-field> </div>
component.ts
changeSelect(item: any, itemName: string): void { // changeSelect 后检查是否需要删除原选项关联的item // 如果change的是父级的选项 递归删除已选 this.checkItemDom(itemName); this.createItemDom(item, itemName); } createItemDom(item: any, itemName: string): void { // 动态添加FromControl this.addFromControl(item.key); const options = []; // 判断选择的item是否还有子级 (select) if (item.type === 'parent') { // 默认parent都是select // 查找子项点展示 item.children.forEach(eleParent => { options.push({ key: eleParent.key, value: eleParent }); }); this.addFromDom(item.key, itemName, item.item_type, '', options, item.type); } else if (item.type === 'item') { if (item.item_type === 'select') { item.value.forEach(eleItem => { options.push({ key: eleItem, value: eleItem }); }); this.addFromDom(item.key, itemName, item.item_type, item.value, options, item.type); } else { // 这里可以扩展多种类型 this.addFromDom(item.key, itemName, item.item_type, item.value, options, item.type); } } } // add/remove itemPushDom // 保存item的name/type/parent 在二维数组中保存子父级关联 addFromDom(name: string, key: string, type: string, value: string, options: any, item_type: string): void { this.itemPushDom.push({ parent: key, name: name, type: type, item: item_type, value: value, options: options }); } checkItemDom(itemName: string): any { for (let i = 0; i < this.itemPushDom.length; i++) { if (this.itemPushDom[i].parent === itemName) { // 根据子父级关系 父级改变 查找相对应的子级删除 Dom和FormGroup this.checkItemDom(this.itemPushDom[i].name); this.delFromControl(this.itemPushDom[i].name); this.itemPushDom.splice(i, 1); } } } addFromControl(name: string): void { this.itemForm.addControl(name, this._formBuilder.control('')); } delFromControl(name: string): void { this.itemForm.removeControl(name); }
Finally, only through this.itemForm.value you can get the selected value
Or save itemPushDom