Angular 动态表单(根据选择联动显示)
首先
记录一下刚刚完成的一个功能
需求是根据固定的层级结构做动态联动,在网上找了很多动态表单的相关教程,大部分都是在最开始加载就生成表单.而我的需求是需要在选择了父级之后再展示父级下的选项
参考了大佬的修仙之路 和 动态生成表单 感谢~
实现
-
准备阶段
配置好已知的层级结构
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]
}
]
},
];
页面上创建初始层级
在初始表单选项上绑定change事件
<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>
页面配置表单的初始选项
itemForm: FormGroup;
// 根据父级的选择 展示的item列表
itemPushDom = [];
ngOnInit(): void {
this.itemForm = this.createFrom();
}
createFrom(): any {
const group = this._formBuilder.group({
'group': this._formBuilder.control('')
});
return group;
}
-
实现动态插入
通过之前的操作 现在我们的页面上已经能看到初始的选项了
接下来就是实现动态插入 , 其实简单来说就是分为两个步骤: Dom插入可选项 和 FormGroup添加项
再加上change父级之后清除之前的选择
Dom插入可选项
需要配合之前初始选项绑定的change事件 传递children的信息
html 上也需要配置好相关的可能出现的类型 通过ngSwtech 展示 (本例类型较少,只有select和input 如果类型较多可以参考官方文档的动态表单 通过component控制出现的类型)
通过 addControl()/removeControl() 对FormGroup 表单项 进行添加和删除(也可以添加验证)
下面直接上代码
component.html (放在上一段form里)
<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.parent === itemName) {
// 根据子父级关系 父级改变 查找相对应的子级删除 Dom和FormGroup
this.checkItemDom(this.itemPushDom.name);
this.delFromControl(this.itemPushDom.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);
}
最后只需要 通过 this.itemForm.value 就可以获得所选的值
或者保存itemPushDom
来源:https://www.cnblogs.com/nhxz001/p/12036553.html |