Angular 7 and form arrays error of cannot find a control with path

时间秒杀一切 提交于 2021-01-28 11:25:32

问题


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": "" } ] }


回答1:


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())
}



回答2:


Ok. so it means you're not adding enough formgroups in array. You are calling create only once. so only first one in array works. when the index goes to 1 from 0 there is no formgroup in formarray. As I understand you want to create formgroup for each row. so you need to call your function many times.

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

instead of creating array every time you should probably push new formgroup to existing formarray.

write a getter for distribution for easier use.

get distribution() {
   this.formGroup.get('distribution') as FormArray;
}    

then you can do

this.distribution.push(this.fb.group({
      'note': new FormControl(''),
      'kit': new FormControl(''),
      'actual_date': new FormControl('')
    }));

for each row. I'm not sure where you are doing create but this would go there for each row.

and keep the formGroup to i instead of i-1 or 0.




回答3:


You have to define form array name above your [formGroup] start like this formArrayName="distribution"



来源:https://stackoverflow.com/questions/55240595/angular-7-and-form-arrays-error-of-cannot-find-a-control-with-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!