Angular 7 和表单数组错误无法找到带有路径的控件 [英] Angular 7 and form arrays error of cannot find a control with path

查看:28
本文介绍了Angular 7 和表单数组错误无法找到带有路径的控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 mat-table 数据源构建一个包含数组的表单组.

我从创建表开始:

<table mat-table [dataSource]="dataSource" *ngIf="total>0" formArrayName="distribution"><ng-container matColumnDef="ind_id"><th mat-h​​eader-cell *matHeaderCellDef>ID </th><td mat-cell *matCellDef="let element">{{element.individual_id}}</td></ng-容器><ng-container matColumnDef="ind_name"><th mat-h​​eader-cell *matHeaderCellDef>名称</th><td mat-cell *matCellDef="let element">{{element.ind_name}}</td></ng-容器><ng-container matColumnDef="ind_status"><th mat-h​​eader-cell *matHeaderCellDef>工业状态</th><td mat-cell *matCellDef="let element">{{element.ind_status}}</td></ng-容器><ng-container matColumnDef="project_kit"><th mat-h​​eader-cell *matHeaderCellDef>套件</th><td mat-cell *matCellDef="let element; let i=index;"><div [formGroupName]="i"><mat-form-field color="warn"外观="填充"><mat-label>试剂盒</mat-label><mat-select formControlName="kit" id="kit" placeholder="Kit"><mat-option *ngFor="let pk of projectKit" [value]="pk.project_kit">{{pk.kit_name}} 部分项目{{pk.project_name}}</mat-option></mat-select></mat-form-field>&nbsp;

</td></ng-容器><ng-container matColumnDef="actual_date"><th mat-h​​eader-cell *matHeaderCellDef>实际日期<td mat-cell *matCellDef="let element; let i=index;"><div [formGroupName]="i"><mat-form-field color="warn" appearance="legacy"><mat-label>实际分布.日期</mat-label><input formControlName="actual_date" matInput [matDatepicker]="picker2" placeholder="实际日期"><mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle><mat-datepicker #picker2></mat-datepicker></mat-form-field>

</td></ng-容器><ng-container matColumnDef="note"><th mat-h​​eader-cell *matHeaderCellDef>注意</th><td mat-cell *matCellDef="let element;let i=index;"><div [formGroupName]="i"><mat-form-field color="warn" appearance="legacy"><mat-label>注意</mat-label><input formControlName="note" matInput type="text" placeholder="Note"></mat-form-field>

</td></ng-容器><ng-container matColumnDef="actions"><th mat-h​​eader-cell *matHeaderCellDef>动作</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>添加</td></ng-容器><tr mat-h​​eader-row *matHeaderRowDef="displayedColumns;sticky: true"></tr><tr mat-row *matRowDef="让行;列:displayColumns;"}"></tr></表单>

对于打字稿:

this.formGroup = this.fb.group({分布:this.fb.array([this.createArray()])});

和 createArray():

createArray(): FormGroup {返回 this.fb.group({'注意':new FormControl(''),'kit': new FormControl(''),'actual_date': new FormControl('')});

当用户上传文件时触发第一个打字稿:

<input #fileInput type="file" formControlName="upload" value="上传 Excel/CSV 文件"(change)="upload($event.target.files)" accept=".xlsx, .xls, .csv"/><button mat-raised-button id="inputFile" color="accent" (click)="reset()"><mat-icon color="warn">取消</mat-icon>重置</表单>

之前上传文件的形式没有错误.

但是当我上传文件时,表单数组出现错误:

<块引用>

错误:找不到路径控制:'分发 -> 1'在 _throwError (forms.js:1790)在 setUpFormContainer (forms.js:1772)在 FormGroupDirective.push

它指向:

<mat-form-field color="warn"外观="填充"><mat-label>试剂盒</mat-label><mat-select formControlName="kit" id="kit" placeholder="Kit"><mat-option *ngFor="let pk of projectKit" [value]="pk.project_kit">{{pk.kit_name}} 部分项目{{pk.project_name}}</mat-option></mat-select></mat-form-field>&nbsp;

编辑

添加{{formGroup.value|后JSON}} 我明白了:

<块引用>

{ "distribution": [ { "note": "", "kit": "", "actual_date": "" } ] }

解决方案

问题是你的数据源,让 i=index 引用数据源的值,如果你的数组中的元素少于你的数据源中的元素,那么你的代码崩溃

如果表格中的所有元素都属于 FormArray,那就简单"了,您可以在 这个stackblitz

有两个键,

如何创建表单

myform:FormGroup=new FormGroup({分布:新 FormArray(ELEMENT_DATA.map(x=>{返回新的表单组({位置:新的FormControl(x.position),名称:新表单控件(x.name),重量:新的FormControl(x.weight),符号:新表单控件(x.symbol),})}))});

以及,我们如何引用控件

<ng-container formArrayName="分发版"><!--看到数据源是 myForm.get('distribution').controls--><table mat-table [dataSource]="myform.get('distribution').controls" class="mat-elevation-z8" ><ng-container matColumnDef="position"><th mat-h​​eader-cell *matHeaderCellDef>号<!--所以,元素"是一个表单组--><td mat-cell *matCellDef="let element;let i=index" [formGroup]="element"><input formControlName="位置" ></td></ng-容器>....</ng-容器></表单>

但是你有一个dataSource"和一个不连接的formArray.您可以创建一个函数来引用数组

get distributionArray(){返回 this.myForm.get('distribution') 作为 FormArray}

并在您的 td 中使用一些类似的内容

<input formControlName="name" ></td>

}

好吧,不一定对所有人都有价值,但数组中的元素必须与数据源中的元素一样多,例如

this.myform:FormGroup=new FormGroup({分布:新的FormArray(ELEMENT_DATA.map(()=>{//只有两个属性为空返回新的表单组({重量:新的FormControl(),符号:新的FormControl(),})}))});

或者使用推送

this.myform:FormGroup=new FormGroup({分布:新的FormArray([])});ELEMENT_DATA.forEach(()=>{(this.myForm.get('distribution') as FormArray).push(this.createArray())}

I am building a form group with an array inside of it, using mat-table data source.

I started by creating the 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>&nbsp;
        </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>

And for the typescript:

this.formGroup = this.fb.group({
      distribution: this.fb.array([
    this.createArray()
  ])
});

And createArray():

createArray(): FormGroup {
    return this.fb.group({
      'note': new FormControl(''),
      'kit': new FormControl(''),
      'actual_date': new FormControl('')
    });

The first typescript is fired when the user upload a file:

<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>

There is no error for the previous form of uploading a file.

But when I upload a file an error appears for the form array:

Error: Cannot find control with path: 'distribution -> 1' at _throwError (forms.js:1790) at setUpFormContainer (forms.js:1772) at FormGroupDirective.push

And it's pointing on:

<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>&nbsp;
          </div>

EDIT

After Adding {{formGroup.value| JSON}} I got this:

{ "distribution": [ { "note": "", "kit": "", "actual_date": "" } ] }

解决方案

the problem is your dataSource, let i=index make reference to the values of the dataSource, if you has less element in your array than in your dataSource your code crash

If all your elements in the table belongs to the FormArray it's "easy", you can see an example in this stackblitz

There are two keys,

one how create the Form

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),

    })}))
  });

And, how We refereed to the controls

<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>

But you has a "dataSource" and a formArray some disconected. You can create a function to referred to the array

get distributionArray()
{
   return this.myForm.get('distribution') as FormArray
}

And use in your td some like

<td mat-cell *matCellDef="let element;let i=index" 
     [formGroup]="distributionArray.at(i)"> 
    <input formControlName="name" > 
</td>

}

well, it's not necesary has value to all, but must there are so many elements in the array as in the dataSource, e.g.

this.myform:FormGroup=new FormGroup({
        distribution:new FormArray(ELEMENT_DATA.map(()=>{
          //only two properties empty
          return new FormGroup({
          weight:new FormControl(),
          symbol:new FormControl(),

        })}))
      });

Or using push

this.myform:FormGroup=new FormGroup({
            distribution:new FormArray([])
});
ELEMENT_DATA.forEach(()=>{
    (this.myForm.get('distribution') as FormArray).push(this.createArray())
}

这篇关于Angular 7 和表单数组错误无法找到带有路径的控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆