Search code examples
angularangular-reactive-formsangular-forms

angular form control required validator only works when their is form input


I've got a reactive form with nested formgroups with some form controls that have required validators.

It seems the validation only occurs when a user inputs values into the form. If the form is submitted with no user interaction, empty textboxes with a required validator show as valid. Is this a normal behavior of angular forms? Am I missing something?

Thanks

Pete

html template:

<form [formGroup]="ticketMarkForm" (ngSubmit)="submitTicket()">
  ..
   <div formGroupName ="systemForm">
     <mat-form-field appearance="outline">
      <mat-label>Pipe Length (Ft):</mat-label>
      <input matInput type="number" required formControlName="pipeLength">
     </mat-form-field>
</div>
 ..
 <button type="submit" mat-stroked-button>Submit</button>
</form>

component typescript:

export class MtMarkFormComponent implements OnInit {
..
ticketMarkForm: FormGroup;
...
constructor(private checkService: MTMarkFormCheckService) { }
 ngOnInit(): void {
 //forms
 this.ticketMarkForm = new FormGroup({
  systemForm: new FormGroup({
    ...
   pipeDiameter: new FormControl(Validators.required),
   ...
  })
  });

}
submitTicket() {
   let pipeDiam:any=this.ticketMarkForm.get('systemForm').get('pipeDiameter');
   this.checkService.CheckRequiredValid(pipeDiam);
   }
}

Service to check form typescript:

export class MTMarkFormCheckService {
 CheckRequiredValid(fc: FormControl) {
        if (fc.invalid) {//if the control is left blank/untouched evaluates to valid.  I've also 
  tried to mark the control as dirty (fc.markAsDirty()) but same result
            alert("invalid");
         }
         else {
           alert("valid");
        }
 }

Solution

  • It is default Angular behavior. You have to define custom error state matcher like this.

    import {FormControl, FormGroupDirective, NgForm} from '@angular/forms';
    import {ErrorStateMatcher} from '@angular/material/core';
    
    export class CustomErrorStateMatcher implements ErrorStateMatcher {
      isErrorState(control: FormControl | null | undefined, form: FormGroupDirective | NgForm | null): boolean {
        if (control == null) {
          return false;
        }
        return control.invalid;
      }
    }
    

    ts :

    export class MtMarkFormComponent implements OnInit {
       :
      public esm = new CustomErrorStateMatcher();
       :
    }
    

    html :

    <input matInput type="number" required formControlName="pipeLength" [errorStateMatcher]="esm">