响应式表单嵌套结构
效果
一层表单动态增加
二层表单嵌套实现(一层数组)
form-nested.component.html
<nz-divider [nzText]="'表单嵌套'"></nz-divider>
<form [formGroup]="validateForm">
<nz-form-item>
<nz-form-label nzSpan="3" nz-col>
工作流名称
</nz-form-label>
<nz-form-control nzSpan="7" nz-col>
<input nz-input type="text" placeholder="请输入工作流名称" formControlName="workFlowName">
</nz-form-control>
<nz-form-label nzSpan="3" nzOffset="1" nz-col>
工作流类型
</nz-form-label>
<nz-form-control nzSpan="7" nz-col>
<input nz-input type="text" placeholder="请输入工作流类型" formControlName="workFlowType">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="3" nz-col>
工作流内容
</nz-form-label>
<button nz-button (click)="addStage()">增加stage</button>
<nz-form-control nzSpan="18">
<div class="workFlowContent" formArrayName="workFlowContent" *ngFor="let content of workFlowContent.controls;
let workflowIndex = index">
<div [formGroupName]="workflowIndex.toString()">
<nz-row>
<nz-form-label nzSpan="3" nz-col>
stage{{workflowIndex + 1}}
</nz-form-label>
<nz-form-control nzOffset="15" nzSpan="3" nz-col>
<button nz-button (click)="removeStage(workflowIndex)">
删除
</button>
</nz-form-control>
</nz-row>
<nz-row>
<nz-form-label nzSpan="3" nz-col>stageName</nz-form-label>
<nz-form-control nz-col nzSpan="7">
<input nz-input type="text" formControlName="stageName">
</nz-form-control>
<nz-form-label nzOffset="1" nzSpan="3" nz-col>stageType</nz-form-label>
<nz-form-control nz-col nzSpan="7">
<input nz-input type="text" formControlName="stageType">
</nz-form-control>
</nz-row>
<!-- <nz-row>
<nz-form-label nzSpan="3" nz-col>stageContent</nz-form-label>
<nz-form-control nz-col nzSpan="18">
<nz-row formArrayName="stageContent"
*ngFor="let stage of stageContent.controls;let stageIndex = index">
<input nz-input [formControlName]="stageIndex.toString()">
</nz-row>
</nz-form-control>
</nz-row> -->
</div>
</div>
</nz-form-control>
</nz-form-item>
</form>
<nz-form-item>
<nz-form-label nzSpan="3" nz-col>
表单的值
</nz-form-label>
<nz-form-control nzSpan="21" nz-col>
{{validateForm.value | json}}
</nz-form-control>
</nz-form-item>
form-nested.component.css
.workFlowContent {
background: #e6f7ff;
border: 1px solid #91d5ff;
padding: 10px;
border-radius: 4px;
}
form-nested.component.ts
import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'uv-form-nested',
templateUrl: './form-nested.component.html',
styleUrls: ['./form-nested.component.css']
})
export class FormNestedComponent implements OnInit {
public validateForm: FormGroup;
constructor(private fb: FormBuilder) {
this.validateForm = this.fb.group({
workFlowName: [null, [Validators.required]],
workFlowType: [null, [Validators.required]],
workFlowContent: this.fb.array([
this.fb.group({
stageName: [null, [Validators.required]],
stageType: [null, [Validators.required]],
// stageContent: this.fb.array([
// this.fb.control(null)
// ]),
})
])
});
}
get workFlowContent(): FormArray {
return this.validateForm.get('workFlowContent') as FormArray;
}
get stageContent(): FormArray {
return this.validateForm.get('stageContent') as FormArray;
}
ngOnInit() {
}
public addStage(): void {
this.workFlowContent.push(
this.fb.group({
stageName: [null, [Validators.required]],
stageType: [null, [Validators.required]],
stageContent: this.fb.array([
this.fb.control(null)
]),
})
);
}
public removeStage(workflowIndex: number): void {
this.workFlowContent.removeAt(workflowIndex);
}
}
提示: 要继续嵌套,在初始化时,不要设置为null,设置为this.fb.array([]),
即可,否则会报错
参考
其他
三层表单嵌套实现(二层数组)
数据格式
autoFormData: T[] = [
{
"key": "title",
"value": "1-1数据",
"ui_type": "editbox",
"ui_title": "1-1"
},
{
"key": "fireTime",
"value": [
{
"key": "fireTime1",
"value": "2-1数据",
"ui_type": "editbox",
"ui_title": "2-1"
},
{
"key": "fireTime2",
"value": "2-2数据",
"ui_type": "editbox",
"ui_title": "2-2"
}
],
"ui_type": "editboxes",
"ui_title": "1-2"
}
]
表单结构
this.validateForm = this.fb.group({
target: [null, [Validators.required]],
opcode: [null, [Validators.required]],
body: this.fb.array([
// 初始化后的形式:
this.fb.group({
key: [null, [Validators.required]],
ui_title: [null, [Validators.required]],
ui_type: [null, [Validators.required]],
value: this.fb.array([
this.fb.group({
key: [null, [Validators.required]],
ui_type: [null, [Validators.required]],
ui_title: [null, [Validators.required]],
value: [null, [Validators.required]],
})
]),
})
])
});
效果
源码
.html
<div>
<button (click)="showFormValue()">查看表单值</button>
<!-- <nz-switch [(ngModel)]="switchValue" (ngModelChange)="change('')"></nz-switch> -->
</div>
<nz-divider></nz-divider>
<form [formGroup]="validateForm">
<div nz-row [nzGutter]="8">
<div nz-col nzSpan="12">
<nz-form-item>
<nz-form-label nz-col nzSpan="3">target</nz-form-label>
<nz-form-control nz-col nzSpan="21">
<input nz-input type="text" formControlName="target">
</nz-form-control>
</nz-form-item>
</div>
</div>
<div nz-row [nzGutter]="8">
<div nz-col nzSpan="12">
<nz-form-item>
<nz-form-label nz-col nzSpan="3">opcode</nz-form-label>
<nz-form-control nz-col nzSpan="21">
<input nz-input type="text" formControlName="opcode">
<!-- <nz-select formControlName="opcode" nzPlaceHolder="请选择" (ngModelChange)="opCodeChange()">
<ng-container *ngFor="let item of opCodeOps">
<nz-option [nzValue]="item.value" [nzLabel]="item.label"></nz-option>
</ng-container>
</nz-select> -->
</nz-form-control>
</nz-form-item>
</div>
</div>
<div nz-row [nzGutter]="8">
<div nz-col nzSpan="24">
<nz-form-item>
<nz-form-label nz-col nzSpan="1">body</nz-form-label>
<nz-row nz-col nzSpan="23">
<button (click)="newValueStr()">增加editbox</button>
<button (click)="newValueArr()">增加editboxes</button>
</nz-row>
</nz-form-item>
</div>
<div nz-col nzSpan="24">
<nz-form-item>
<nz-form-control nzOffset="4" nzSpan="20">
<div class="workFlowContent" formArrayName="body" *ngFor="let content of body.controls;
let workflowIndex = index">
<div [formGroupName]="workflowIndex.toString()">
<!-- <nz-row>formGroupName: {{workflowIndex}}</nz-row> -->
<nz-row nz-col nzOffset="22">
<button nz-button (click)="deleteValue(workflowIndex)">删除</button>
</nz-row>
<nz-row>
<nz-form-label nzSpan="4" nz-col>ui_title</nz-form-label>
<nz-form-control nz-col nzSpan="7">
<input nz-input type="text" formControlName="ui_title">
</nz-form-control>
</nz-row>
<nz-row>
<nz-form-label nzSpan="4" nz-col>ui_type</nz-form-label>
<nz-form-control nz-col nzSpan="7">
<input nz-input type="text" formControlName="ui_type">
</nz-form-control>
</nz-row>
<nz-row>
<nz-form-label nzSpan="4" nz-col>key</nz-form-label>
<nz-form-control nz-col nzSpan="7">
<input nz-input type="text" formControlName="key">
</nz-form-control>
</nz-row>
<!-- value为字符串 -->
<ng-container *ngIf="getValue(content).controls == undefined; else other_ediboxes">
<nz-row>
<nz-form-label nzSpan="4">
value
</nz-form-label>
<nz-form-control nz-col nzSpan="7">
<input nz-input type="text" formControlName="value">
</nz-form-control>
</nz-row>
</ng-container>
<!-- value为数组 -->
<ng-template #other_ediboxes>
<nz-row>
<nz-form-label nz-col nzSpan="4">
value
</nz-form-label>
<nz-row nz-col nzSpan="2">
<button (click)="newSubValueStr(workflowIndex)">增加</button>
</nz-row>
</nz-row>
<nz-row>
<nz-form-control nzOffset="4" nz-col nzSpan="20">
<div formArrayName="value" class="stageContent" *ngFor="let stage of getValue(content).controls;
let stageIndex = index">
<div [formGroupName]="stageIndex.toString()">
<!-- <nz-row>formGroupName: {{stageIndex}}</nz-row> -->
<!-- {{vJson(stage)}} -->
<!-- {{getControlsValueByKey(stage, "value")}} -->
<nz-row nz-col nzOffset="22" style="margin-bottom: 10px;">
<button (click)="deleteSubValue(workflowIndex, stageIndex)">删除</button>
</nz-row>
<nz-row>
<nz-form-label nzSpan="8" nz-col>ui_title</nz-form-label>
<nz-form-control nzSpan="16" nz-col>
<input nz-input type="text" formControlName="ui_title" placeholder="请输入">
</nz-form-control>
</nz-row>
<nz-row>
<nz-form-label nzSpan="8" nz-col>ui_type</nz-form-label>
<nz-form-control nzSpan="16" nz-col>
<input nz-input type="text" formControlName="ui_type" placeholder="请输入">
</nz-form-control>
</nz-row>
<nz-row>
<nz-form-label nzSpan="8" nz-col>key</nz-form-label>
<nz-form-control nzSpan="16" nz-col>
<input nz-input type="text" formControlName="key" placeholder="请输入">
</nz-form-control>
</nz-row>
<nz-row>
<nz-form-label nzSpan="8" nz-col>value</nz-form-label>
<nz-form-control nzSpan="16" nz-col>
<ng-container>
<input nz-input type="text" formControlName="value" placeholder="请输入">
</ng-container>
</nz-form-control>
</nz-row>
</div>
</div>
</nz-form-control>
</nz-row>
<nz-row>
</nz-row>
</ng-template>
</div>
</div>
</nz-form-control>
</nz-form-item>
</div>
</div>
</form>
<nz-form-item>
<nz-form-label nzSpan="2" nz-col>
表单的值
</nz-form-label>
<nz-form-control nzSpan="22" nz-col>
{{validateForm.value | json}}
</nz-form-control>
</nz-form-item>
<div nz-row [nzGutter]="10">
<div nz-col nzSpan="12">
<button nz-button nzType="primary" (click)="submit()">提交</button>
</div>
</div>
.ts
import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { UhttpService } from '@uviews/conn-server';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ShareService } from '../service/share.service';
import { HttpClient } from '@angular/common/http';
interface T {
key: string,
value: any,
ui_type: string,
ui_title: string
}
@Component({
selector: 'uv-add-conf2',
templateUrl: './add-conf2.component.html',
styleUrls: ['./add-conf2.component.css']
})
export class AddConf2Component implements OnInit {
vJson(e: any) {
// console.log(e)
// console.log(e.controls)
// console.log(e.controls["value"].value)
console.log(JSON.stringify(e, undefined, 2))
}
// 根据key获取FormControls的值
getControlsValueByKey(e: any, key: string) {
// console.log(e.controls[key].value)
return e.controls[key].value
}
public validateForm!: FormGroup;
constructor(
public shareService: ShareService,
private fb: FormBuilder,
private message: NzMessageService,
private uHttp: UhttpService,
private http: HttpClient
) {
}
ngOnInit() {
this.initFormGroup()
}
// 初始化基础表单
initFormGroup() {
this.validateForm = this.fb.group({
target: [null, [Validators.required]],
opcode: [null, [Validators.required]],
body: this.fb.array([
// 初始化后的形式:
// this.fb.group({
// key: [null, [Validators.required]],
// ui_title: [null, [Validators.required]],
// ui_type: [null, [Validators.required]],
// value: this.fb.array([
// this.fb.group({
// key: [null, [Validators.required]],
// ui_type: [null, [Validators.required]],
// ui_title: [null, [Validators.required]],
// value: [null, [Validators.required]],
// })
// ]),
// })
])
});
}
// 获取body的formControls
get body(): FormArray {
return this.validateForm.get('body') as FormArray;
}
// 获取gcontent对应的value的formControls
getValue(content: any) {
return content.get('value') as FormArray;
}
// 新建FormControl类型的value,即value为字符串
newValueStr() {
this.body.push(
this.fb.group({
key: ['', [Validators.required]],
ui_type: ['', [Validators.required]],
ui_title: ['', [Validators.required]],
value: ['', [Validators.required]]
})
)
}
// 新建FormArray类型的value,即value为数组
newValueArr() {
this.body.push(
this.fb.group({
key: ['', [Validators.required]],
ui_type: ['', [Validators.required]],
ui_title: ['', [Validators.required]],
value: this.fb.array([
this.fb.group({
key: ['', [Validators.required]],
ui_type: ['', [Validators.required]],
ui_title: ['', [Validators.required]],
value: ['', [Validators.required]]
})
]),
})
);
}
// 删除第一层value
deleteValue(index: number) {
console.log(index)
this.body.removeAt(index);
}
// 新建第二层FormControl类型的value,即value为字符串
newSubValueStr(bodyIndex: number) {
(this.body.at(bodyIndex).get('value') as FormArray).push(
this.fb.group({
key: ['', [Validators.required]],
ui_type: ['', [Validators.required]],
ui_title: ['', [Validators.required]],
value: ['', [Validators.required]]
})
);
}
// 删除第二层value
deleteSubValue(valueIndex: number, subValueIndex: number) {
(this.body.at(valueIndex).get('value') as FormArray).removeAt(subValueIndex);
}
showFormValue() {
console.log(this.validateForm)
console.log(JSON.stringify(this.validateForm.value, undefined, 2))
}
submit() {
this.vJson(this.validateForm.value)
if (this.validateForm.valid) {
const data = this.validateForm.value
this.http.patch(`http://127.0.0.1:8000/api/control_console/${data.target}/${data.opcode}`, data.body).subscribe(
(res: any) => {
if (res.code == 0) {
this.message.success("添加成功")
this.validateForm.reset()
} else {
this.message.error(res.message)
}
}
)
}
else {
Object.values(this.validateForm.controls).forEach(control => {
console.log(control)
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
if(control.value != null) {
// console.log(control.valid)
this.message.error("请填写完整")
}
});
}
}
}