我有以下课程:
class License {
name:string;
.. lots of other fields.
nameAttributes:NameAttributes[];
}
class nameAttributes:NameAttributes{
index:number;
attribute:string;
}
我知道我可以像这样创建表单,但是这需要我手动创建每个字段(控件),并且每次许可证类更改时,我都必须使用新字段来更新类和这个formGroup。
this.licenseForm = formBuilder.group({
name:['name value'],
otherFields:['their values'],
nameAttributes: this.formBuilder.array([
this.formBuilder.group({
index:[1],
attribute:["attr1"]
}),
this.formBuilder.group({
index:[2],
attribute:["attr2"]
})
])
});
如果我可以将许可证类传递到formBuilder中,它会自动创建必要的FormGroups并根据其名称使它们可用,那么我将更喜欢,因此以下内容将创建两个组,一个“ license”组和一个嵌套的“ nameAttributes”组,其中包含所有与license和nameAttributes相关的控件。
this.licenseForm = formBuilder.group({
license:formBuilder.group(license)
});
我是否错过了某些东西?或者,如果没有一些严肃的课堂自省代码,这是不可能的吗?
答案 0 :(得分:1)
如果您的对象有数据,您当然可以做到
看看这个stackblitz
您具有类似
的功能 createForm(data:any):FormGroup
{
const group=new FormGroup({});
for (let key in data)
{
if (Array.isArray(data[key])) //if is an array
{ //first create the formArray
group.addControl(key,new FormArray([this.createForm(data[key][0])]))
for (let i=1;i<data[key].length;i++) //after add the rest of the elements
(group.get(key) as FormArray).push(this.createForm(data[key][i]))
}
else
{
if (typeof(data[key])=="object") //if is an object we add a formGroup
group.addControl(key,this.createForm(data[key]))
else //add a simple control
group.addControl(key,new FormControl(data[key]))
}
}
return group
}
并命名为
this.form=this.createForm(this.obj)
答案 1 :(得分:1)
@cyberthreat,如所保证,这是带有ngx-sub-form
的版本。
首先,这是现场演示的链接:https://stackblitz.com/edit/angular-td2iew
现在让我们看看它是如何构建的:
app.component.ts
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public licenseUpdated(license: License): void {
console.log(JSON.stringify(license, null, 2));
}
}
app.component.html
<app-license-form (licenseUpdated)="licenseUpdated($event)"></app-license-form>
这里没什么好想的,但是请注意一个事实,我们绝对不在乎如何从该组件中获取许可证数据。我们只想在有更新的情况下得到警告。
license-form.component.ts
@Component({
selector: 'app-license-form',
templateUrl: './license-form.component.html',
styleUrls: ['./license-form.component.css']
})
export class LicenseFormComponent extends NgxRootFormComponent<License> {
@DataInput()
@Input('license')
public dataInput: License | null | undefined;
@Output('licenseUpdated') public dataOutput: EventEmitter<License> = new EventEmitter();
protected getFormControls(): Controls<License> {
return {
name: new FormControl(null, [Validators.required]),
nameAttributes: new FormControl(null, [Validators.required]),
};
}
}
license-form.component.html
<form [formGroup]="formGroup">
<div>
Name<br>
<input type="text" [formControlName]="formControlNames.name">
</div>
<div>
License attributes<br>
<app-license-attributes-form [formControlName]="formControlNames.nameAttributes"></app-license-attributes-form>
</div>
<button class="save" (click)="manualSave()">Save form</button>
(look at your console to see when the form is saved!)
</form>
<div class="values">
Form group values
<pre>{{ formGroupValues | json }}</pre>
</div>
如果您不熟悉ngx-sub-form
,在这里,我邀请您阅读该博客文章:https://dev.to/maxime1992/building-scalable-robust-and-type-safe-forms-with-angular-3nf9和/或该项目的自述文件:https://github.com/cloudnc/ngx-sub-form
这里要注意的重要一点是,我们只关心原始值,其他所有内容都分解为子表单组件!此外,关于表单,所有内容都输入了安全类型(ts 和 html!)。
许可证属性-form.component.ts
interface LicenseAttributesForm {
attributes: NameAttribute[];
}
@Component({
selector: 'app-license-attributes-form',
templateUrl: './license-attributes-form.component.html',
styleUrls: ['./license-attributes-form.component.css'],
providers: subformComponentProviders(LicenseAttributesFormComponent)
})
export class LicenseAttributesFormComponent extends NgxSubFormRemapComponent<NameAttribute[], LicenseAttributesForm> {
protected getFormControls(): Controls<LicenseAttributesForm> {
return {
attributes: new FormArray([], [Validators.required]),
};
}
protected transformToFormGroup(obj: NameAttribute[]): LicenseAttributesForm {
return {
attributes: obj ? obj : [],
};
}
protected transformFromFormGroup(formValue: LicenseAttributesForm): NameAttribute[] | null {
return formValue.attributes;
}
public addAttribute(): void {
(this.formGroupControls.attributes as FormArray).push(
this.createFormArrayControl(
'attributes',
{
index: null,
attribute: null
}
)
);
}
public removeAttribute(index: number): void {
(this.formGroupControls.attributes as FormArray).removeAt(index);
}
public createFormArrayControl(
key: any,
value: any,
): FormControl {
return new FormControl(value, [Validators.required]);
}
}
license-attributes-form.component.html
<div [formGroup]="formGroup">
<button (click)="addAttribute()">Add an attribute</button>
<div
class="attribute"
formArrayName="attributes"
*ngFor="let attribute of formGroupControls.attributes.controls; let i = index"
>
<app-license-attribute-form [formControl]="attribute"></app-license-attribute-form>
<button (click)="removeAttribute(i)">Delete</button>
</div>
</div>
最后是最后一个
许可证属性-form.component.ts
@Component({
selector: 'app-license-attribute-form',
templateUrl: './license-attribute-form.component.html',
styleUrls: ['./license-attribute-form.component.css'],
providers: subformComponentProviders(LicenseAttributeFormComponent)
})
export class LicenseAttributeFormComponent extends NgxSubFormComponent<NameAttribute> {
protected getFormControls(): Controls<NameAttribute> {
return {
index: new FormControl(null, [Validators.required]),
attribute: new FormControl(null, [Validators.required]),
};
}
}
license-attribute-form.component.html
<form [formGroup]="formGroup">
<div>
Index<br>
<input type="number" [formControlName]="formControlNames.index">
</div>
<div>
Attribute<br>
<input type="text" [formControlName]="formControlNames.attribute">
</div>
</form>
我真的鼓励您浏览Stackblitz并进行演示,这将是理解和发现我的想法的更简单方法:)