angularangular-materialangular-formsangular2-form-validation

Angular reactive forms form-group validations are working only for any one row in Mat-table


I have Mat table with multiple rows, with add button ,on click of it, adds a new row. i want to add validations for all the rows ,right now my code below is taking a validation only for any one row.

my component.html

<form [formGroup]="auditUserValidation">
<mat-table [dataSource]="dataSource">

<ng-container matColumnDef="Audit">

<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element">
<mat-select formControlName="name" placeholder="Pls select">
<mat-option [value]="audit" *ngFor="let name of nameList">{{name.firstname}}</mat-option>
</mat-select></mat-cell>

</ng-container>

<ng-container matColumnDef="Country">

<mat-header-cell *matHeaderCellDef> Country</mat-header-cell>
<mat-cell *matCellDef="let element">
<mat-select formControlName="Country" placeholder="Pls select">
<mat-option [value]="audit" *ngFor="let country of CountryList">{{country.name}}</mat-option>
</mat-select></mat-cell>

</ng-container>

<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>


Save button which i want to disable if all rows not selected

<button type="button" (click)="addElement()"> <i class="material-icons">add</i>Add</button>
<button type="button" [disabled]='auditUserValidation.invalid' (click)="submitReport()">Save</button>

my component.ts file

  auditUserValidation: FormGroup;

  constructor(private formBuilder: FormBuilder }   
  ngOnInit() {
    this.auditUserValidation = this.formBuilder.group({
      name: ['', [Validators.required]],
      Country: ['', [Validators.required]],
    });
}

Solution

  • In general, you has a formArray. As always, we has a function that return a formGroup

    createGroup(data:any)
      {
        data=data || {name:'',surname:''}
        return new FormGroup({
          name: new FormControl(data.name,Validators.required),
          surname: new FormControl(data.surname,Validators.required)
        })
      }
    

    After create the formArray, we make the "dataSource" formArray.controls

      this.dataSource=this.myformArray.controls
    

    So, the only is ask about

    element.get('name').touched &&element.get('name').errors
    

    e.g.

    <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
      <!-- Name Column -->
      <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef> Name </th>
        <td mat-cell *matCellDef="let element">
           <input [formControl]="element.get('name')">
                  <div *ngIf="element.get('name').touched 
                     && element.get('name').errors">required</div>
               </td>
      </ng-container>
    
      <!-- Surname Column -->
      <ng-container matColumnDef="surname">
        <th mat-header-cell *matHeaderCellDef> Surname </th>
            <td mat-cell *matCellDef="let element">
    
           <input [formControl]="element.get('surname')">
           <div *ngIf="element.get('surname').touched 
             && element.get('surname').errors">required</div>
           </td>
      </ng-container>
      <!--if we want delete the row (*)-->
      <ng-container matColumnDef="delete">
        <th mat-header-cell *matHeaderCellDef> </th>
           <td mat-cell *matCellDef="let i = index;">
              <button mat-button (click)="remove(i)">delete</button>
           </td>
      </ng-container>
    
    
      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
    </table>
    

    See the stackblitz

    Updated add and remove rows

    (*) the displayedColumns becomes like

    displayedColumns: string[] = ['name','surname','delete'];
    

    Two functions serve to add and remove rows

      add() {
        this.myformArray.push(this.createGroup(null));
        this.table.renderRows(); //<--see that we need refresh the table
      }
      remove(index: number) {
        this.myformArray.removeAt(index);
        this.table.renderRows();  //<--see that we need refresh the table
      }
    

    where table is

      @ViewChild(MatTable, { static: false }) table: MatTable<any>;