我有一个分层的对象,它描述了一个不太简单的布局,其中包含输入字段等,就像这样:
{
"type": "HorizontalLayout",
"margin": false,
"children": [
{
"type": "TextField",
"id": "code",
"caption": "Code of product",
"width": "100px"
},
{
"type": "NumberField",
"id": "amount",
"caption": "Amount of pieces"
}
]
}
此对象的深度不是固定的,可以包含许多嵌套容器和输入字段。将对象呈现为具有所有所需元素的DOM片段并将其附加到所需元素不是很困难,但是我如何才能将呈现的输入绑定到现有的FormGroup?
更新:更具体地说-如何将用document.createElement
创建的输入元素绑定到现有的FormGroup
?
答案 0 :(得分:0)
在您的类中创建一个FormGroup,然后递归遍历children数组中的每个项目,然后向该表单添加一个新控件。
Here是有关如何在FormGroup中使所有控件位于同一级别的快速示例。 HTML将显示RawValues表单,因此您可以看到HTML表单。
在此示例中,'data'属性是固定的,但是您可以修改此属性并将其他一些数据传递到setupForm方法中。
import { Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, FormControl, Validators} from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular';
form: FormGroup;
data: {} = {
"type": "HorizontalLayout",
"margin": false,
"children": [
{
"type": "TextField",
"id": "code",
"caption": "Code of product",
"width": "100px"
},
{
"type": "NumberField",
"id": "amount",
"caption": "Amount of pieces",
}
]
};
constructor(private fb: FormBuilder){}
ngOnInit(){
this.form = this.fb.group({});
// pass the data form which form controls should be created
this.setupForm(this.data);
}
setupForm(field: any){
if(field.children && field.children.length){
const children = field.children;
// Loop through each item in the children array and add a form control
for(const item of children){
// This assumes that all your fields have unique Ids
this.form.addControl(item.id, new FormControl('test', [Validators.required]))
// Process nested fields
this.setupForm(item);
}
}
}
}
您提供的样本数据具有顶级对象。我怀疑您可能有多个“ HorizontalLayout”。如果是这种情况,您可以修改setupForm以处理数组而不是对象。
setupForm还将查找“ children”属性,并递归调用setupForm。这使您可以进行多层嵌套。
希望这会有所帮助。
答案 1 :(得分:0)
constructor(private formBuilder: FormBuilder) { }
dynamicForm: FormGroup;
ngOnInit() {
// set the fieldNames variable to generate form
const fieldNames = ['field1', 'field2', 'field3'];
this.dynamicForm = this.generateForm(fieldNames );
}
generateForm(fieldNames: string[]): FormGroup { // this is your form group
const formFields: any = { };
fieldNames.forEach(name=> {
formFields[name] = [null, [Validators.required]];
});
return this.formBuilder.group(formFields);
}
答案 2 :(得分:0)
最后,我最终在组件的模板中创建了输入元素。该组件是为布局对象的每个节点递归创建的(如article of Ben Nadel中所述(谁值得为此多谢))。 FormGroup的一个实例被显式传递到所有NodeComponent / NodeTreeComponent,这使得将输入元素绑定到它很容易。
描述布局的对象示例:
{
"type": "Container",
"id": "filter",
"children": [
{
"type": "HorizontalLayout",
"spacing": true,
"children": [
{
"type": "TextField",
"id": "code",
"caption": "Код",
"width": "100px"
},
{
"type": "TextField",
"id": "label",
"caption": "Наименование",
"width": "200px"
},
{
"type": "TextField",
"id": "days",
"caption": "Дней",
"width": "100px"
},
{
"type": "TextField",
"id": "months",
"caption": "Месяцев",
"width": "100px"
},
{
"type": "Check3Box",
"id": "isActive",
"caption": "Активен",
"height": "20px",
"alignment": "bottom_left"
},
{
"type": "Check3Box",
"id": "isAbsDeleted",
"caption": "Удален в АБС",
"height": "20px",
"alignment": "bottom_left"
}
]
}
]
}
main.component.html的一部分
<ng-template [ngIf]="filterForm">
<form [formGroup]="my_awesome_form">
<my-tree [rootNode]="elements" [form]="my_awesome_form"></my-tree>
</form>
</ng-template>
main.component.ts的一部分
// form creation
public my_awesome_form = new FormGroup({});
// saving a layout object to a public variable
public elements = some_data_service.getLayout();
// getting input fields from the layout object
const inputs = Utils.deepFind(this.elements, 'caption', '');
// привязываем поля к форме
inputs.forEach((input) => {
this.filterForm.addControl(input.id, new FormControl(null));
});
TreeComponent
import {Component} from "@angular/core";
import {LayoutElement} from "@toolkit/models/layout.model";
import {FormGroup} from "@angular/forms";
@Component({
selector: "my-tree",
inputs: [
"rootNode",
"form"
],
outputs: [],
template: `<my-tree-node [node]="rootNode" [form]="form"></my-tree-node>`
})
export class TreeComponent {
public rootNode: LayoutElement | null;
public form: FormGroup;
constructor() {
this.rootNode = null;
}
}
TreeNodeComponent
import {Component} from "@angular/core";
import {LayoutElement} from "@toolkit/models/layout.model";
import {FormGroup} from "@angular/forms";
@Component({
selector: "my-tree-node",
inputs: [
"node",
"form"
],
outputs: [],
template:
`
<ng-template [ngIf]="node && node.type">
<span [ngSwitch]="node.type" [formGroup]="form">
<!-- пример создания контейнера -->
<div *ngSwitchCase="'Container'">
<div *ngIf="node.children">
<ng-template ngFor let-child [ngForOf]="node.children">
<my-tree-node [node]="child" [form]="form"></my-tree-node>
</ng-template>
</div>
</div>
<!-- пример создания поля ввода -->
<ng-template [ngSwitchCase]="'TextField'">
<input type="text" [attr.placeholder]="node.caption" [formControlName]="node.id"/>
</ng-template>
<!-- обработка не зарегистрированного типа -->
<div *ngSwitchDefault>
<div class="p-3 mb-2 bg-danger text-white">Element of type "{{ node.type }}" can't be processed!</div>
</div>
</span>
</ng-template>
`
})
export class TreeNodeComponent {
public node: LayoutElement | null;
public form: FormGroup;
constructor() {
this.node = null;
}
}
感谢所有尝试提供帮助的人!顺便说一句,对于这么大的代码块,我没找到如何插入扰流器