嵌套的自定义FormArray组件不与具有FormArrayName的子窗体绑定 [英] nested custom FormArray component doesn't bind with child form with FormArrayName
问题描述
我尝试使用CVA编写2个嵌套表格.问题是当我将第二个from绑定到formControl时没有用数据初始化.
我有主表单:
this.requestForm = this.fb.group({
garageId: 0,
routes: new FormArray([
new FormGroup({
addressPointId: new FormControl,
municipalityId: new FormControl,
regionId: new FormControl,
rvId: new FormControl,
sequenceNumber: new FormControl,
settlementId: new FormControl,
regionName: new FormControl,
municipalityName: new FormControl,
settlementName: new FormControl,
description: new FormControl,
})
]),
endDateTime: 0,
});
在主要形式的html中,我使用formArrayName将路由绑定到.
<app-cva-form-array formArrayName="routes"></app-cva-form-array>
组件 CVA-FORM-ARRAY 具有.
form = new FormArray([
new FormGroup({
addressPointId: new FormControl,
municipalityId: new FormControl,
regionId: new FormControl,
rvId: new FormControl,
sequenceNumber: new FormControl,
settlementId: new FormControl,
regionName: new FormControl,
municipalityName: new FormControl,
settlementName: new FormControl,
description: new FormControl,
})
]);
这里的一切都很好.我将数组中的每个formGroup绑定到子组件CVA-FORM.
<app-cva-form [formControl]="route" (blur)="onTouched()"></app-cva-form>
CVA-FORM 对于每个formGroup,我都创建了单独的组件,以防万一我想使用组件本身而不是整个数组.
form: FormGroup = new FormGroup({
regionName: new FormControl,
regionId: new FormControl,
municipalityName: new FormControl,
municipalityId: new FormControl,
sequenceNumber: new FormControl,
settlementName: new FormControl,
settlementId: new FormControl,
addressPointId: new FormControl,
description: new FormControl,
rvId: new FormControl,
});
主表单<-to-> app-cva-form-array绑定由于某些原因无法正常工作.
这些形式的思想来自 kara关于angulaconnect的演讲. 解决方案
在使用自定义表单控件"时,需要考虑到您向cursom表单控件提供了一个表单控件(不是FormArray,不是FormGroup). FormControl具有一个数组或对象作为值,但是您不必对此感到困惑.(*)
您可以在 所以,在mainForm中,我们有 在cvc-form数组中,当我们赋值时创建formArray 最后是cva形式 (*)是的,我们习惯于看到FormControl具有一个字符串或数字作为值,但是没有人禁止我们将该值作为对象或数组(例如ng-bootstrap DatePicker存储一个对象{year:.. month:..,day ..},mat-multiselect存储数组,...) 更新当然,我们可以向控件提供来自服务或类似服务的数据.我们唯一需要考虑的是如何提供数据.通常,我喜欢创建一个接收数据或null并返回FormControl的函数 其中IData是接口 和IDetail另一个界面 然后我们可以有一个复杂的数据,例如(大对象很抱歉) 然后只需要 堆叠闪电战(如果已更新) I tried to have 2 nested forms using CVA. the problem is the second from isn't initialized with data when I bind it to a formControl. I have MAIN-FORM: In main-form html I bind routes to with formArrayName. Component CVA-FORM-ARRAY has. Everything from here works just fine. I bind each formGroup in the array to child component CVA-FORM. CVA-FORM
for each formGroup I created separate component in case I want to use component itself not the whole array. the main-form <--to--> app-cva-form-array binding doesn't work for some reason. The idea of these forms comes from kara's talk on angulaconnect.
here are her slides. help plz! When you use "custom Form Control", you need take account that you feed the cursom Form Control with a Form Control (not FormArray, not FormGroup). The FormControl has as value an array or an object, but you need not confussed about this.(*) You can see in work in stackblitz That's your form is like I've create a const to export to simply the code. MY const expor is So, in mainForm we have In cvc-form array create the formArray when we give value Finally, the cva-form (*) Yes, we are used to seeing that a FormControl has as a value a string or a number, but no one forbids us that the value is an object or an array (for example, ng-bootstrap DatePicker stores an object {year: .. month: .., day ..}, mat-multiselect stores an array, ...) Update Of course we can feed our control with data from a service or similar. The only thing we must take account is how we give the data. As usually I like make a function that received a data or null and return a FormControl where IData is an interface and IDetail another interface Then we can have a complex data like (sorry for the large object) Then only need make The stackblitz if updated 这篇关于嵌套的自定义FormArray组件不与具有FormArrayName的子窗体绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! ngOnInit() {
let routes:any[]=[];
routes.push({...dataI});
this.requestForm = new FormGroup({
garageId: new FormControl(0),
routes: new FormControl(routes),
endDateTime: new FormControl(0)
})
}
<mat-card [formGroup]="requestForm" style="background: #8E8D8A">
<app-cva-form-array formControlName="routes"></app-cva-form-array>
</mat-card>
writeValue(v: any) {
this.form=new FormArray([]);
for (let value of v)
this.form.push(new FormControl(value))
this.form.valueChanges.subscribe(res=>
{
if (this.onChange)
this.onChange(this.form.value)
})
}
<form [formGroup]="form" >
<mat-card *ngFor="let route of form.controls;
let routeIndex = index; let routeLast = last;">
<button (click)="deleteRoute(routeIndex)">
cancel
</button>
<app-cva-form [formControl]="route" (blur)="onTouched()"></app-cva-form>
</form>
writeValue(v: any) {
this.form=new FormGroup({});
Object.keys(dataI).forEach(x=>{
this.form.addControl(x,new FormControl())
})
this.form.setValue(v, { emitEvent: false });
this.form.valueChanges.subscribe(res=>{
if (this.onChanged)
this.onChanged(this.form.value)
})
}
<div [formGroup]="form">
<mat-form-field class="locationDate">
<input formControlName="regionName">
<mat-autocomplete #region="matAutocomplete"
(optionSelected)="selectedLocation($event)">
<mat-option *ngFor="let region of regions"
[value]="region">
{{region.regionName}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="locationDate">
<input formControlName="municipalityName"
[matAutocomplete]="municipality"
(blur)="onTouched()"
[readonly]="checked || this.form.value.regionId < 1">
....
</form>
getForm(data: any): FormGroup {
data = data || {} as IData;
return new FormGroup({
garageId: new FormControl(data.garageId),
routes: new FormControl(data.routes),
endDateTime: new FormControl(data.endDateTime)
})
}
export interface IData {
garageId: number;
routes: IDetail[];
endDateTime: any
}
export interface IDetail {
addressPointId: string;
...
description: string;
}
let data = {
garageId: 1,
routes: [{
addressPointId: "adress",
municipalityId: "municipallyty",
regionId: "regionId",
rvId: "rvId",
sequenceNumber: "sequenceNumber",
settlementId: "settlementId",
regionName: "regionName",
municipalityName: "municipalityName",
settlementName: "settlementName",
description: "description",
},
{
addressPointId: "another adress",
municipalityId: "another municipallyty",
regionId: "another regionId",
rvId: "another rvId",
sequenceNumber: "another sequenceNumber",
settlementId: "another settlementId",
regionName: "another regionName",
municipalityName: "another municipalityName",
settlementName: "another settlementName",
description: "another description",
}],
endDateTime: new Date()
}
this.requestForm = this.getForm(data);
this.requestForm = this.fb.group({
garageId: 0,
routes: new FormArray([
new FormGroup({
addressPointId: new FormControl,
municipalityId: new FormControl,
regionId: new FormControl,
rvId: new FormControl,
sequenceNumber: new FormControl,
settlementId: new FormControl,
regionName: new FormControl,
municipalityName: new FormControl,
settlementName: new FormControl,
description: new FormControl,
})
]),
endDateTime: 0,
});
<app-cva-form-array formArrayName="routes"></app-cva-form-array>
form = new FormArray([
new FormGroup({
addressPointId: new FormControl,
municipalityId: new FormControl,
regionId: new FormControl,
rvId: new FormControl,
sequenceNumber: new FormControl,
settlementId: new FormControl,
regionName: new FormControl,
municipalityName: new FormControl,
settlementName: new FormControl,
description: new FormControl,
})
]);
<app-cva-form [formControl]="route" (blur)="onTouched()"></app-cva-form>
form: FormGroup = new FormGroup({
regionName: new FormControl,
regionId: new FormControl,
municipalityName: new FormControl,
municipalityId: new FormControl,
sequenceNumber: new FormControl,
settlementName: new FormControl,
settlementId: new FormControl,
addressPointId: new FormControl,
description: new FormControl,
rvId: new FormControl,
});
//in main.form
this.requestForm = new FormGroup({
garageId: new FormControl(0),
routes: new FormControl(routes), //<--routes will be an array of object
endDateTime: new FormControl(0)
})
//in cva-form-array
this.form=new FormArray([new FormControl(...)]); //<-this.form is a
//formArray of FormControls NOT of formGroup
//finally in your cva-form
this.form=new FormGroup({});
this.form=formGroup({
addressPointId: new FormControl(),
municipalityId: new FormControl(),
...
})
export const dataI = {
addressPointId: "",
municipalityId: "",
regionId: "",
rvId: "",
sequenceNumber: "",
settlementId: "",
regionName: "",
municipalityName: "",
settlementName: "",
description: "",
}
ngOnInit() {
let routes:any[]=[];
routes.push({...dataI});
this.requestForm = new FormGroup({
garageId: new FormControl(0),
routes: new FormControl(routes),
endDateTime: new FormControl(0)
})
}
<mat-card [formGroup]="requestForm" style="background: #8E8D8A">
<app-cva-form-array formControlName="routes"></app-cva-form-array>
</mat-card>
writeValue(v: any) {
this.form=new FormArray([]);
for (let value of v)
this.form.push(new FormControl(value))
this.form.valueChanges.subscribe(res=>
{
if (this.onChange)
this.onChange(this.form.value)
})
}
<form [formGroup]="form" >
<mat-card *ngFor="let route of form.controls;
let routeIndex = index; let routeLast = last;">
<button (click)="deleteRoute(routeIndex)">
cancel
</button>
<app-cva-form [formControl]="route" (blur)="onTouched()"></app-cva-form>
</form>
writeValue(v: any) {
this.form=new FormGroup({});
Object.keys(dataI).forEach(x=>{
this.form.addControl(x,new FormControl())
})
this.form.setValue(v, { emitEvent: false });
this.form.valueChanges.subscribe(res=>{
if (this.onChanged)
this.onChanged(this.form.value)
})
}
<div [formGroup]="form">
<mat-form-field class="locationDate">
<input formControlName="regionName">
<mat-autocomplete #region="matAutocomplete"
(optionSelected)="selectedLocation($event)">
<mat-option *ngFor="let region of regions"
[value]="region">
{{region.regionName}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="locationDate">
<input formControlName="municipalityName"
[matAutocomplete]="municipality"
(blur)="onTouched()"
[readonly]="checked || this.form.value.regionId < 1">
....
</form>
getForm(data: any): FormGroup {
data = data || {} as IData;
return new FormGroup({
garageId: new FormControl(data.garageId),
routes: new FormControl(data.routes),
endDateTime: new FormControl(data.endDateTime)
})
}
export interface IData {
garageId: number;
routes: IDetail[];
endDateTime: any
}
export interface IDetail {
addressPointId: string;
...
description: string;
}
let data = {
garageId: 1,
routes: [{
addressPointId: "adress",
municipalityId: "municipallyty",
regionId: "regionId",
rvId: "rvId",
sequenceNumber: "sequenceNumber",
settlementId: "settlementId",
regionName: "regionName",
municipalityName: "municipalityName",
settlementName: "settlementName",
description: "description",
},
{
addressPointId: "another adress",
municipalityId: "another municipallyty",
regionId: "another regionId",
rvId: "another rvId",
sequenceNumber: "another sequenceNumber",
settlementId: "another settlementId",
regionName: "another regionName",
municipalityName: "another municipalityName",
settlementName: "another settlementName",
description: "another description",
}],
endDateTime: new Date()
}
this.requestForm = this.getForm(data);