Search code examples
angularformarrayangular-material-table

Angular Form Array And Angular Material Table. Error: Could not find column with id "position"


I'm trying to do an Angular Material Table with Form Array, but I'm getting the error:

Could not find column with id "position".

I saw a lot of answers about the directive matColumnDef, but I have this at my code. Like this one and the name is the same with the dataSource. Like this one

   <ng-container matColumnDef="position">
                  <th mat-header-cell *matHeaderCellDef> No. </th>
                  <td mat-cell *matCellDef="let element" [formControlName]='arrayOfProperties[0]' > {{element.position}} </td>
              </ng-container>

You can see my code here: https://stackblitz.com/edit/angular-tyu1y4?file=src/main.ts

you can find the error at the browser console

I think it'something about the way that I am building the table here:

<div formArrayName="tourTable" *ngFor="let controls of tourTable.controls; let i = index;">
          <div [formGroupName]="i">

Solution

  • Mannage a FormArrray with a mat-table it's not equal than another table.

    The simpler way is use as dataSource: tourTable.controls. Yes, we can use an array to "feed" the dataSource, so we are using an array of FormGroups (that really is a formArray.controls)

    As we know the elements are formGroups, so we can use this in our td

    <ng-container matColumnDef="position">
       <th mat-header-cell *matHeaderCellDef > No. </th>
    
       <!--see how we say that we are using as formGroup the "element"-->
       <td mat-cell *matCellDef="let element" [formGroup]="element">
    
            <input [formControlName]='arrayOfProperties[0]' >
       </td>
    </ng-container>
    

    Yes it's a bit "bizarro" repeat the [formGroup] in each element, the another way is create a function that return the formControl at index

    getControl(index:number,name:string)
    {
       return this.tourTable.at(index).get(name) as FormControl
    }
    

    And use [FormControl]instead of formControlName

    <ng-container matColumnDef="position">
       <th mat-header-cell *matHeaderCellDef > No. </th>
    
       <td mat-cell *matCellDef="let element;let index=index" >
    
            <input [formControl]='getControl(index,arrayOfProperties[0])' >
       </td>
    </ng-container>
    

    NOTE: Don't forget use this.table.renderRows() when add a new element to the array

    NOTE2: I'm not prety sure if was necessary in strict mode use a getter to the controls

      get controls(){
        return this.tourTable.controls as FormGroup[]
      }
    

    And use

    <table mat-table [dataSource]="controls">
    

    stackblitz