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

1.7k views Asked by At

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;
 }  
1

There are 1 answers

0
Sunil Shrestha On BEST ANSWER

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