Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 嵌套的自定义FormArray组件不与具有FormArrayName的子窗体绑定_Angular_Typescript_Angular Reactive Forms_Controlvalueaccessor - Fatal编程技术网

Angular 嵌套的自定义FormArray组件不与具有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]

我尝试使用CVA创建两个嵌套表单。问题是,当我将第二个from绑定到formControl时,它没有用数据初始化

我有以下主要表格:

在主表单html中,我使用formArrayName将路由绑定到

 <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=>{…您的代码..}