1

I am getting data from server to the component.

This data contains something called Family Relation having multiple values, that can be selected from the drop down list to change the original family relation value.

What I want is to create an array of form control inputs using Reactive Forms, to display drop down list at each row of the angular material table data source.

Here is a working stackblitz that give you a great idea of the problem.

Here is the scripts. I replaced the server data with 2 array examples (familyRelationArray and data):

The getFamilyRelation() method gets the type of relations and display them. At the stackblitz, you can see that the drop down list menu is at the bottom (which is not a problem on my computer):

getFamilyRelation() {

    //This function gets data from server, but for testing purposes, I filled an array:
    this.familyRelationArray = [
      {
        id: 1,
        type: 'Father'
      },
      {
        id: 2,
        type: 'Mother'
      },
      {
        id: 3,
        type: 'Sister'
      }
    ]
  }

The getData() method is to get original data and display them in material table by applying the result to dataSource having the type of dataSource = new MatTableDataSource<any>();:

getData() {
    //For testing purposes, I filled an array of data instead of getting data from servers
    this.data = [
      {
        name: 'xyz', head_hh: 'Yes', fr: 'Parent', frid: 2, ms: 'Married', sts: 'Active', age: '61', iid: 123
      },
      {
        name: 'yxz', head_hh: 'No', fr: 'Child', frid: 3, ms: 'Single', sts: 'Active', age: '25', iid: 221
      },
    ]
    this.showEmpty = false;
    this.dataSource = new MatTableDataSource((this.data));
    this.resultsLength = this.data.length;
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;


  }

Here is the FormArray method, which create the drop list at each row:

constructor(private fb: FormBuilder) {
    this.formGroup = this.fb.group({
      test: this.createArray()
    })
  }

createArray(): FormArray {
    return new FormArray(this.dataSource.data.map(item => new FormGroup({
      fr: new FormControl(item.frid)
    })));
  }

The html script, contain the created form array using formArrayName="test" and formGroupName="i" where i is the index of the created drop list:

<form [formGroup]="formGroup">
    <mat-card class="example-card">
        <mat-card-content>
            <div class="example-container mat-elevation-z8">
                <table mat-table [dataSource]="dataSource" matSort formArrayName="test">

                    <ng-container matColumnDef="name">
                        <th mat-header-cell *matHeaderCellDef> Name </th>
                        <td mat-cell *matCellDef="let element"> <b>{{element.name}}</b> </td>

          </ng-container>


          <ng-container matColumnDef="head_hh">
            <th mat-header-cell *matHeaderCellDef> Head Of HH </th>
            <td mat-cell *matCellDef="let element"> {{element.head_hh}} </td>
          </ng-container>


          <ng-container matColumnDef="fr" >
            <th mat-header-cell *matHeaderCellDef> Family Rel. </th>
            <td mat-cell *matCellDef="let element; let i = index;">
              <div [formGroupName]="i">
                <mat-form-field color="warn" appearance="outline">
                    <mat-label>Drop List</mat-label>
                    <mat-select id="family_relation" formControlName="fr" placeholder="Drop List">                 
                          <mat-option *ngFor="let familyRelation of familyRelationArray;" [value]="frid">
                        {{familyRelation.type}}
                      </mat-option>
                    </mat-select>
                  </mat-form-field>&nbsp;
                </div>
                  <i>Original Value: {{element.fr}}</i>
            </td>
          </ng-container>

          <ng-container matColumnDef="ms">
            <th mat-header-cell *matHeaderCellDef> Marital Sts. </th>
            <td mat-cell *matCellDef="let element"> {{element.ms}} </td>
          </ng-container>
          <ng-container matColumnDef="status">
            <th mat-header-cell *matHeaderCellDef> Status </th>
            <td mat-cell *matCellDef="let element"> {{element.sts}} </td>
          </ng-container>
          <ng-container matColumnDef="age">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Age </th>
            <td mat-cell *matCellDef="let element"> {{element.age}} </td>
          </ng-container>

          <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
          <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
        </table>
        <mat-paginator [length]="resultsLength" [pageSizeOptions]="[15, 25, 50, 100]"></mat-paginator>
      </div>
    </mat-card-content>
    <mat-card-actions>
    </mat-card-actions>
  </mat-card>
</form>

The error is that I can't set the value of each drop list to be equal to the orignal value displayed under each drop down list, and an error at the console saying:

ERROR Error: Cannot find control with path: 'test

I tried the solutions of this post on stack but nothing worked.

bat7
  • 836
  • 1
  • 8
  • 22
alim1990
  • 4,656
  • 12
  • 67
  • 130

0 Answers0