Angular 嵌套的自定义FormArray组件不与具有FormArrayName的子窗体绑定
我尝试使用CVA创建两个嵌套表单。问题是,当我将第二个from绑定到formControl时,它没有用数据初始化 我有以下主要表格: 在主表单html中,我使用formArrayName将路由绑定到Angular 嵌套的自定义FormArray组件不与具有FormArrayName的子窗体绑定,angular,typescript,angular-reactive-forms,controlvalueaccessor,Angular,Typescript,Angular Reactive Forms,Controlvalueaccessor,我尝试使用CVA创建两个嵌套表单。问题是,当我将第二个from绑定到formControl时,它没有用数据初始化 我有以下主要表格: 在主表单html中,我使用formArrayName将路由绑定到 <app-cva-form-array formArrayName="routes"></app-cva-form-array> 这里的一切都很好。我将数组中的每个formGroup绑定到子组件CVA-FORM <app-cva-form [formControl]
<app-cva-form-array formArrayName="routes"></app-cva-form-array>
这里的一切都很好。我将数组中的每个formGroup绑定到子组件CVA-FORM
<app-cva-form [formControl]="route" (blur)="onTouched()"></app-cva-form>
由于某些原因,主表单应用cva表单数组绑定无法工作
这些形式的概念来源于
救命啊 您需要将更新后的表单数据从子组件传递到父组件。我使用了this.form.valueChanges方法来检测更改,然后将表单值发送到父组件 父组件: HTML代码:
<app-cva-form-array formArrayName="routes" (onChildFormValueChange)="onFormChange($event)"></app-cva-form-array>
No change:)
子组件:
HTML代码:
<app-cva-form-array formArrayName="routes" (onChildFormValueChange)="onFormChange($event)"></app-cva-form-array>
No change:)
TS代码:
public onFormChange(form): void {
this.requestForm = form;
}
@Output() onChildFormValueChange: EventEmitter<any> = new EventEmitter<any>();
registerEvent() {
this.form.valueChanges.subscribe(() => {
this.onFormValueChange()
});
}
public onFormValueChange(): void {
this.onChildFormValueChange.emit(this.form);
}
您需要将更新后的表单数据从子组件传递到父组件。我使用了this.form.valueChanges方法来检测更改,然后将表单值发送到父组件 父组件: HTML代码:
<app-cva-form-array formArrayName="routes" (onChildFormValueChange)="onFormChange($event)"></app-cva-form-array>
No change:)
子组件:
HTML代码:
<app-cva-form-array formArrayName="routes" (onChildFormValueChange)="onFormChange($event)"></app-cva-form-array>
No change:)
TS代码:
public onFormChange(form): void {
this.requestForm = form;
}
@Output() onChildFormValueChange: EventEmitter<any> = new EventEmitter<any>();
registerEvent() {
this.form.valueChanges.subscribe(() => {
this.onFormValueChange()
});
}
public onFormValueChange(): void {
this.onChildFormValueChange.emit(this.form);
}
我认为这里的问题是FormarAyname不是NG_VALUE_访问器/DefaultValueAccessor的输入 另请注意: 她的例子是静态父母->多个孩子。。。意味着1对多,而不是动态的。您正在尝试静态 父级到多个动态子级->从formArray构建的孙子关系,然后尝试将孙子窗体动态链接到父级formArrayIndex,该父级formArrayIndex通过子级传递给孙子。你的stackblitz偏离了她所教授的结构,并且肯定引入了一些讲座中未涉及的新挑战 探索如何在父级迭代FormArray并从该循环中实例化子->孙关系可能是一个可行的解决方案,这样您就不会向下传递整个数组,而只传递将应用的formGroup
<h1>MAIN FORM</h1>
{{ requestForm.value | json }}
<div *ngFor="let route of requestForm.get('routes').controls">
<app-cva-form-array formControl="route" (onChildFormValueChange)="onFormChange($event)"></app-cva-form-array>
</div>
我相信这里要理解的关键是formArray只是其子公司的一个组织容器。。。在这种情况下,如果没有其他逻辑的帮助,它将无法完成您希望它完成的任务
目前似乎没有必要的功能来
接受formArray作为输入,迭代/动态管理阵列,
并将更改链接回父窗体阵列
我认为这里的问题是FormarAyname不是NG_VALUE_访问器/DefaultValueAccessor的输入 另请注意: 她的例子是静态父母->多个孩子。。。意味着1对多,而不是动态的。您正在尝试静态 父级到多个动态子级->从formArray构建的孙子关系,然后尝试将孙子窗体动态链接到父级formArrayIndex,该父级formArrayIndex通过子级传递给孙子。你的stackblitz偏离了她所教授的结构,并且肯定引入了一些讲座中未涉及的新挑战 探索如何在父级迭代FormArray并从该循环中实例化子->孙关系可能是一个可行的解决方案,这样您就不会向下传递整个数组,而只传递将应用的formGroup
<h1>MAIN FORM</h1>
{{ requestForm.value | json }}
<div *ngFor="let route of requestForm.get('routes').controls">
<app-cva-form-array formControl="route" (onChildFormValueChange)="onFormChange($event)"></app-cva-form-array>
</div>
我相信这里要理解的关键是formArray只是其子公司的一个组织容器。。。在这种情况下,如果没有其他逻辑的帮助,它将无法完成您希望它完成的任务
目前似乎没有必要的功能来
接受formArray作为输入,迭代/动态管理阵列,
并将更改链接回父窗体阵列
使用自定义表单控件时,需要考虑向cursom表单控件提供非FormArray、非FormGroup的表单控件。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(),
...
})
因此,在主要形式中,我们有
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>
其中IData是一个接口
export interface IData {
garageId: number;
routes: IDetail[];
endDateTime: any
}
export interface IDetail {
addressPointId: string;
...
description: string;
}
和另一个接口
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);
stackblitz如果更新当您使用自定义表单控件时,您需要考虑向cursom表单控件提供非FormArray、非FormGroup的表单控件。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(),
...
})
因此,在主要形式中,我们有
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>
其中IData是一个接口
export interface IData {
garageId: number;
routes: IDetail[];
endDateTime: any
}
export interface IDetail {
addressPointId: string;
...
description: string;
}
和另一个接口
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);
stackblitz如果更新我不清楚您是否询问背景表格?是的。如果你看看JSON。你会看到主窗体背景窗体与其他窗体不同步。请查看posetd答案我不清楚是什么
你在问背景表格吗?是的。如果你看看JSON。您将看到主窗体背景窗体与其他窗体不同步。请查看posetd answer这只提供单向绑定。虽然我知道怎么做两种方式,但它仍然不是我要找的。如果您检查cva表单数组如何绑定到cva表单,我想为主表单cva表单数组实现类似的绑定。使用cva的目的是简化代码,而不是使用额外的函数。我在问题的底部添加了关于代码来源的外部资源。@Vato Nope如果更改主窗体,则cva窗体数组不会更改,这是双向绑定。如果您在主窗体中编写regionName:newFormControl'asdfa',它会将子组件regionnames保留为null。在这里,如果您从父级添加数组,则它不只是子级的bount,反之亦然。但无论如何,正如我所说,使用cva不需要任何函数。这只提供了单向绑定。虽然我知道怎么做两种方式,但它仍然不是我要找的。如果您检查cva表单数组如何绑定到cva表单,我想为主表单cva表单数组实现类似的绑定。使用cva的目的是简化代码,而不是使用额外的函数。我在问题的底部添加了关于代码来源的外部资源。@Vato Nope如果更改主窗体,则cva窗体数组不会更改,这是双向绑定。如果您在主窗体中编写regionName:newFormControl'asdfa',它会将子组件regionnames保留为null。在这里,如果您从父级添加数组,则它不只是子级的bount,反之亦然。但是无论如何,正如我说的,使用cva不需要任何函数。谢谢你的回答!我可以使用接口而不是常量吗?我不希望表单数组绑定到主表单。或者你认为我应该把const放在不同的文件中吗?你好,我试着把解决方案放在我的项目中。我尝试加载已经存在的初始数据。我遵循与你相同的代码。但我注意到,当我使用数据初始化时,它不会传输到子对象,当我尝试添加另一个路由时,它会将索引放在数组对象的前面。像这样的路由:{0:{regionId:…municipalityId:}}。这可能也是初始化的问题。你知道解决方案是什么吗?@Vato,我更新了答案和stackblitz,我希望这能有所帮助。关于使用接口或常量,我尝试过,但没有结果:,但接口和常量当然可以在主界面之外-form@Eliseo,谢谢,效果很好。但一旦添加地址,它仍然会在数组前面添加索引。它使数组{0:{}1:{}…}等。在添加数组之前,看起来很好[{},{},{},{}],以避免表达式更改。。。有时使用setTimeOut=>{…您的代码..}是非常有用的。谢谢您的回答!我可以使用接口而不是常量吗?我不希望表单数组绑定到主表单。或者你认为我应该把const放在不同的文件中吗?你好,我试着把解决方案放在我的项目中。我尝试加载已经存在的初始数据。我遵循与你相同的代码。但我注意到,当我使用数据初始化时,它不会传输到子对象,当我尝试添加另一个路由时,它会将索引放在数组对象的前面。像这样的路由:{0:{regionId:…municipalityId:}}。这可能也是初始化的问题。你知道解决方案是什么吗?@Vato,我更新了答案和stackblitz,我希望这能有所帮助。关于使用接口或常量,我尝试过,但没有结果:,但接口和常量当然可以在主界面之外-form@Eliseo,谢谢,效果很好。但一旦添加地址,它仍然会在数组前面添加索引。它使数组{0:{}1:{}…}等。在添加数组之前,看起来很好[{},{},{},{}],以避免表达式更改。。。有时使用setTimeOut=>{…您的代码..}