Search code examples
angulartypescriptangular6

How to validate mat input text field inside a mat table in angular 6?


I have a mat table in where Im getting values from backend and displaying. Now Im trying to add a new typeable field "cmnts", where it should be a text field and have validations. My issue here is validation is applying to every row & whatever text im entering in the first row , that is appearing in all the rows. Is my form control name should be unique for each row. In that case how should i use in ts file. Could you please suggest?

My html code is like below:

 <table mat-table [dataSource]="dataSource" class="" matSort > 
        <tbody>
        <th><td>...</td></th>
         <ng-container matColumnDef="cmts">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Comments    
        </th>
        <form [formGroup]="commentsForm" >
        <td mat-cell *matCellDef="let element">
            <span *ngIf="element?.id=='321'">
            <mat-form-field>
                <input matInput id="cmnts" formControlName="cmnts" required>
                <mat-error *ngIf="submitted || h.cmnts.errors || h.cmnts.touched">
                    <span *ngIf="h.cmnts.errors?.required">cmnts is Required</span>
                </mat-error>
                <mat-error *ngIf="submitted || h.cmnts.errors">
                    <span *ngIf="h.cmnts.errors?.minlength"> Minimum length should be 10</span>
                </mat-error>
                <mat-error *ngIf="submitted || h.cmnts.errors">
                    <span *ngIf="h.cmnts.errors?.maxlength"> Maximum length should be 30 </span>
                </mat-error> 
            </mat-form-field>     
            </span>
        </td>  
        </form>      
       </ng-container>

My Ts file :

 commentsForm: FormGroup;

 this.commentsForm = this.fb.group({
    cmnts:  ['', [Validators.required,Validators.minLength(10), Validators.maxLength(40)]],
 })

 get h() { return this.commentsForm.controls; }
 

I have tried using formArray as below also. still unable to set validations separtely for each row. Please suggest. //Updated

     <form [formGroup]="CmntsForm" >
     <td mat-cell *matCellDef="let element;let rowIndex = index">
      <span *ngIf="element?.sts=='A'">
       <mat-form-field> 
         <input matInput id="cmnts" formControlName="cmnts" required>
       </mat-form-field>
       </span>
      </td>

ts:

this.CmntsForm = this.fb.group({
        cmnts: this.fb.array( ['', [Validators.required,Validators.minLength(1), Validators.maxLength(30)]])

})

get cmnts(){
    return this.CmntsForm.controls["cmnts"] as FormArray;
 }  

Solution

  • You need to configure form array of form group with own validation rules for each row. Here is an example with the latest version of angular hope it helps.

    HTML:

    <form [formGroup]="commentsForm">
      <table formArrayName="usercomments" mat-table [dataSource]="dataSource">
        <ng-container matColumnDef="id">
         <th mat-header-cell *matHeaderCellDef> ID </th>
         <td mat-cell *matCellDef="let item"> {{item.id}} </td>
        </ng-container>
       <ng-container matColumnDef="name">
         <th mat-header-cell *matHeaderCellDef> Name </th>
         <td mat-cell *matCellDef="let item"> {{item.name}} </td>
       </ng-container>
       <ng-container matColumnDef="comment">
        <th mat-header-cell *matHeaderCellDef> Comment </th>
        <td mat-cell *matCellDef="let item; let rowIndex=index">
          <div [formGroupName]="rowIndex">
              <mat-form-field>
                <input
                  placeholder="Enter comment"
                  formControlName="comment"
                  matInput
                />
                <mat-error *ngIf="commentFormArray.controls[rowIndex].get('comment')?.hasError('required')">
                  Comment is required.
                </mat-error>
        </mat-form-field>
          </div> 
        </td>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
      </table>
      <button mat-raised-button [disabled]="commentsForm.invalid">Submit</button>
    </form>
    

    TS:

    export interface UserComment {
      id: number;
      name: string;
      comment: string;
    }
    
    export class UserCommentsComponent implements OnInit {
      displayedColumns: string[] = ['id', 'name', 'comment'];
      dataSource: UserComment[]  = [
         { id: 1, name: 'John', comment: ''},
        { id: 2, name: 'Abram', comment: ''}
      ];
    
     commentsForm: FormGroup;
     constructor(private fb: FormBuilder){}
     ngOnInit() {
        this.commentsForm = this.fb.group({
         usercomments: this.fb.array(this.loadUserComment(this.dataSource))
        });
     }
    
     get commentFormArray() : FormArray {
      return this.commentsForm.controls["usercomments"] as FormArray
     }
     private loadUserComment(comments: UserComment[]): FormGroup [] {
      return comments.map((item: UserComment) => 
        this.createCommentFormGroup(item));
     }
    
     private createCommentFormGroup(item: UserComment) : FormGroup{
        return new FormGroup({
          name: new FormControl(item.name),
          comment: new FormControl(item.comment, [Validators.required])})
     }
    }