Angular 7 和表单数组错误找不到带路径的控件
Angular 7 and form arrays error of cannot find a control with path
我正在使用 mat-table
数据源构建一个包含数组的表单组。
我首先创建 table:
<form *ngIf="formGroup" [formGroup]="formGroup">
<table mat-table [dataSource]="dataSource" *ngIf="total>0" formArrayName="distribution">
<ng-container matColumnDef="ind_id">
<th mat-header-cell *matHeaderCellDef> ID </th>
<td mat-cell *matCellDef="let element">{{element.individual_id}}</td>
</ng-container>
<ng-container matColumnDef="ind_name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element">{{element.ind_name}}</td>
</ng-container>
<ng-container matColumnDef="ind_status">
<th mat-header-cell *matHeaderCellDef> Ind. Status </th>
<td mat-cell *matCellDef="let element">{{element.ind_status}}</td>
</ng-container>
<ng-container matColumnDef="project_kit">
<th mat-header-cell *matHeaderCellDef> Kits </th>
<td mat-cell *matCellDef="let element; let i=index;">
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="fill">
<mat-label>Kits</mat-label>
<mat-select formControlName="kit" id="kit" placeholder="Kit">
<mat-option *ngFor="let pk of projectKit" [value]="pk.project_kit">{{pk.kit_name}} part of project
{{pk.project_name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</td>
</ng-container>
<ng-container matColumnDef="actual_date">
<th mat-header-cell *matHeaderCellDef> Actual Date </th>
<td mat-cell *matCellDef="let element; let i=index;">
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="legacy">
<mat-label>Actual Dist. Date</mat-label>
<input formControlName="actual_date" matInput [matDatepicker]="picker2" placeholder="Actual Date">
<mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
</div>
</td>
</ng-container>
<ng-container matColumnDef="note">
<th mat-header-cell *matHeaderCellDef> Note </th>
<td mat-cell *matCellDef="let element;let i=index;">
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="legacy">
<mat-label>Note</mat-label>
<input formControlName="note" matInput type="text" placeholder="Note">
</mat-form-field>
</div>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element">
<button mat-raised-button color="warn" type="submit" color="warn" (click)="addDist(element)">
<mat-icon>add</mat-icon> Add
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"
}"></tr>
</table>
</form>
对于打字稿:
this.formGroup = this.fb.group({
distribution: this.fb.array([
this.createArray()
])
});
和 createArray():
createArray(): FormGroup {
return this.fb.group({
'note': new FormControl(''),
'kit': new FormControl(''),
'actual_date': new FormControl('')
});
用户上传文件时触发第一个打字稿:
<form [formGroup]="uploadForm" role="form">
<input #fileInput type="file" formControlName="upload" value="Upload Excel/CSV file"
(change)="upload($event.target.files)" accept=".xlsx, .xls, .csv" />
<button mat-raised-button id="inputFile" color="accent" (click)="reset()">
<mat-icon color="warn">cancel</mat-icon>Reset
</button>
</form>
之前上传文件的形式没有报错
但是当我上传文件时,表单数组出现错误:
Error: Cannot find control with path: 'distribution -> 1'
at _throwError (forms.js:1790)
at setUpFormContainer (forms.js:1772)
at FormGroupDirective.push
它指向:
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="fill">
<mat-label>Kits</mat-label>
<mat-select formControlName="kit" id="kit" placeholder="Kit">
<mat-option *ngFor="let pk of projectKit" [value]="pk.project_kit">{{pk.kit_name}} part of project
{{pk.project_name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
编辑
添加 {{formGroup.value| JSON}}
后我得到了这个:
{ "distribution": [ { "note": "", "kit": "", "actual_date": "" } ] }
您必须像这样 formArrayName="distribution"
在 [formGroup]
开头定义表单数组名称
好的。所以这意味着你没有在数组中添加足够的表单组。您只调用一次创建。所以只有数组中的第一个有效。当索引从 0 变为 1 时,formarray 中没有 formgroup。据我了解,您想为每一行创建表单组。所以你需要多次调用你的函数。
this.formGroup = this.fb.group({
distribution: this.fb.array([
this.createArray()
])
});
与其每次都创建数组,不如将新的表单组推送到现有的表单数组中。
写一个getter分发方便使用
get distribution() {
this.formGroup.get('distribution') as FormArray;
}
那么你可以
this.distribution.push(this.fb.group({
'note': new FormControl(''),
'kit': new FormControl(''),
'actual_date': new FormControl('')
}));
每一行。我不确定你在哪里创建,但这会为每一行去那里。
并将 formGroup 保留为 i 而不是 i-1 或 0。
问题出在您的数据源上,让 i=index 引用数据源的值,如果数组中的元素少于数据源中的元素,您的代码会崩溃
如果 table 中的所有元素都属于 FormArray,它是 "easy",您可以在 this stackblitz
中查看示例
有两个键,
如何创建表单
myform:FormGroup=new FormGroup({
distribution:new FormArray(ELEMENT_DATA.map(x=>{
return new FormGroup({
position:new FormControl(x.position),
name:new FormControl(x.name),
weight:new FormControl(x.weight),
symbol:new FormControl(x.symbol),
})}))
});
以及,我们如何引用控件
<form *ngIf="myform" [formGroup]="myform">
<ng-container formArrayName="distribution">
<!--see that datasource is myForm.get('distribution').controls-->
<table mat-table [dataSource]="myform.get('distribution').controls" class="mat-elevation-z8" >
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<!--so, "element" is a formGroup-->
<td mat-cell *matCellDef="let element;let i=index" [formGroup]="element"> <input formControlName="position" > </td>
</ng-container>
....
</table>
</ng-container>
</form>
但是您有一个 "dataSource" 和一个 formArray 一些断开连接。您可以创建一个函数来引用数组
get distributionArray()
{
return this.myForm.get('distribution') as FormArray
}
并在你的 td 中使用一些像
<td mat-cell *matCellDef="let element;let i=index"
[formGroup]="distributionArray.at(i)">
<input formControlName="name" >
</td>
}
好吧,它不一定对所有人都有价值,但数组中的元素必须与数据源中的元素一样多,例如
this.myform:FormGroup=new FormGroup({
distribution:new FormArray(ELEMENT_DATA.map(()=>{
//only two properties empty
return new FormGroup({
weight:new FormControl(),
symbol:new FormControl(),
})}))
});
或使用推送
this.myform:FormGroup=new FormGroup({
distribution:new FormArray([])
});
ELEMENT_DATA.forEach(()=>{
(this.myForm.get('distribution') as FormArray).push(this.createArray())
}
我正在使用 mat-table
数据源构建一个包含数组的表单组。
我首先创建 table:
<form *ngIf="formGroup" [formGroup]="formGroup">
<table mat-table [dataSource]="dataSource" *ngIf="total>0" formArrayName="distribution">
<ng-container matColumnDef="ind_id">
<th mat-header-cell *matHeaderCellDef> ID </th>
<td mat-cell *matCellDef="let element">{{element.individual_id}}</td>
</ng-container>
<ng-container matColumnDef="ind_name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element">{{element.ind_name}}</td>
</ng-container>
<ng-container matColumnDef="ind_status">
<th mat-header-cell *matHeaderCellDef> Ind. Status </th>
<td mat-cell *matCellDef="let element">{{element.ind_status}}</td>
</ng-container>
<ng-container matColumnDef="project_kit">
<th mat-header-cell *matHeaderCellDef> Kits </th>
<td mat-cell *matCellDef="let element; let i=index;">
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="fill">
<mat-label>Kits</mat-label>
<mat-select formControlName="kit" id="kit" placeholder="Kit">
<mat-option *ngFor="let pk of projectKit" [value]="pk.project_kit">{{pk.kit_name}} part of project
{{pk.project_name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</td>
</ng-container>
<ng-container matColumnDef="actual_date">
<th mat-header-cell *matHeaderCellDef> Actual Date </th>
<td mat-cell *matCellDef="let element; let i=index;">
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="legacy">
<mat-label>Actual Dist. Date</mat-label>
<input formControlName="actual_date" matInput [matDatepicker]="picker2" placeholder="Actual Date">
<mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
</div>
</td>
</ng-container>
<ng-container matColumnDef="note">
<th mat-header-cell *matHeaderCellDef> Note </th>
<td mat-cell *matCellDef="let element;let i=index;">
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="legacy">
<mat-label>Note</mat-label>
<input formControlName="note" matInput type="text" placeholder="Note">
</mat-form-field>
</div>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element">
<button mat-raised-button color="warn" type="submit" color="warn" (click)="addDist(element)">
<mat-icon>add</mat-icon> Add
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"
}"></tr>
</table>
</form>
对于打字稿:
this.formGroup = this.fb.group({
distribution: this.fb.array([
this.createArray()
])
});
和 createArray():
createArray(): FormGroup {
return this.fb.group({
'note': new FormControl(''),
'kit': new FormControl(''),
'actual_date': new FormControl('')
});
用户上传文件时触发第一个打字稿:
<form [formGroup]="uploadForm" role="form">
<input #fileInput type="file" formControlName="upload" value="Upload Excel/CSV file"
(change)="upload($event.target.files)" accept=".xlsx, .xls, .csv" />
<button mat-raised-button id="inputFile" color="accent" (click)="reset()">
<mat-icon color="warn">cancel</mat-icon>Reset
</button>
</form>
之前上传文件的形式没有报错
但是当我上传文件时,表单数组出现错误:
Error: Cannot find control with path: 'distribution -> 1' at _throwError (forms.js:1790) at setUpFormContainer (forms.js:1772) at FormGroupDirective.push
它指向:
<div [formGroupName]="i">
<mat-form-field color="warn" appearance="fill">
<mat-label>Kits</mat-label>
<mat-select formControlName="kit" id="kit" placeholder="Kit">
<mat-option *ngFor="let pk of projectKit" [value]="pk.project_kit">{{pk.kit_name}} part of project
{{pk.project_name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
编辑
添加 {{formGroup.value| JSON}}
后我得到了这个:
{ "distribution": [ { "note": "", "kit": "", "actual_date": "" } ] }
您必须像这样 formArrayName="distribution"
[formGroup]
开头定义表单数组名称
好的。所以这意味着你没有在数组中添加足够的表单组。您只调用一次创建。所以只有数组中的第一个有效。当索引从 0 变为 1 时,formarray 中没有 formgroup。据我了解,您想为每一行创建表单组。所以你需要多次调用你的函数。
this.formGroup = this.fb.group({
distribution: this.fb.array([
this.createArray()
])
});
与其每次都创建数组,不如将新的表单组推送到现有的表单数组中。
写一个getter分发方便使用
get distribution() {
this.formGroup.get('distribution') as FormArray;
}
那么你可以
this.distribution.push(this.fb.group({
'note': new FormControl(''),
'kit': new FormControl(''),
'actual_date': new FormControl('')
}));
每一行。我不确定你在哪里创建,但这会为每一行去那里。
并将 formGroup 保留为 i 而不是 i-1 或 0。
问题出在您的数据源上,让 i=index 引用数据源的值,如果数组中的元素少于数据源中的元素,您的代码会崩溃
如果 table 中的所有元素都属于 FormArray,它是 "easy",您可以在 this stackblitz
中查看示例有两个键,
如何创建表单
myform:FormGroup=new FormGroup({
distribution:new FormArray(ELEMENT_DATA.map(x=>{
return new FormGroup({
position:new FormControl(x.position),
name:new FormControl(x.name),
weight:new FormControl(x.weight),
symbol:new FormControl(x.symbol),
})}))
});
以及,我们如何引用控件
<form *ngIf="myform" [formGroup]="myform">
<ng-container formArrayName="distribution">
<!--see that datasource is myForm.get('distribution').controls-->
<table mat-table [dataSource]="myform.get('distribution').controls" class="mat-elevation-z8" >
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<!--so, "element" is a formGroup-->
<td mat-cell *matCellDef="let element;let i=index" [formGroup]="element"> <input formControlName="position" > </td>
</ng-container>
....
</table>
</ng-container>
</form>
但是您有一个 "dataSource" 和一个 formArray 一些断开连接。您可以创建一个函数来引用数组
get distributionArray()
{
return this.myForm.get('distribution') as FormArray
}
并在你的 td 中使用一些像
<td mat-cell *matCellDef="let element;let i=index"
[formGroup]="distributionArray.at(i)">
<input formControlName="name" >
</td>
}
好吧,它不一定对所有人都有价值,但数组中的元素必须与数据源中的元素一样多,例如
this.myform:FormGroup=new FormGroup({
distribution:new FormArray(ELEMENT_DATA.map(()=>{
//only two properties empty
return new FormGroup({
weight:new FormControl(),
symbol:new FormControl(),
})}))
});
或使用推送
this.myform:FormGroup=new FormGroup({
distribution:new FormArray([])
});
ELEMENT_DATA.forEach(()=>{
(this.myForm.get('distribution') as FormArray).push(this.createArray())
}