Search code examples
angularangular-material2angular-validation

Angular 7 How to trigger mat-error manually?


I have a a control which I want to validate:

  <mat-form-field class="example-full-width">
    <input matInput placeholder="Title " required [formControl]="titleFormControl">
    <mat-error *ngIf="titleFormControl.hasError('required')">
      Title is <strong>required</strong>
    </mat-error>
    <mat-error *ngIf="titleFormControl.hasError('duplicate')">
      Name already used
    </mat-error>
  </mat-form-field>

and in the component I have something like

titleFormControl = new FormControl('', {
    validators: [
      Validators.required,
      Validators.minLength(4)
    ],
  });

  ngOnInit(): void {
      this.titleFormControl.valueChanges
  .pipe(distinctUntilChanged()).subscribe(this.isNameDuplicate.bind(this))
  }

 isNameDuplicate(): void {
    const ret = this.data.findIndex((item, index) =>
      index !== this.selSheetIndex && item.id >= 0 && this.titleFormControl.value === item.title) >= 0;
    if (ret) {
      this.titleFormControl.setErrors({ 'duplicate': true });
      this.titleFormControl.markAsDirty(); // doesn't help neither :-/
    }
  }

If I change the text the mat-error is displayed immediately if the title is missing. When I change the content so isNameDuplicate() results in an error the control has an error 'duplicate'

I would expect that mat-error is displayed immediately but somehow this is not true. The evaluation of mat-error (for 'duplicate') is only triggered if I change the focus, e.g. change into another field. (while 'required' is displayed immediately)

Is there a way to trigger the evaluation manually so the 'duplicate' error mat-error is displayed as well immediately?

Note: I know I could do it with an error matcher but frankly said I have no clue how to apply a check with a given list. Therefore I am looking for a solution for this approach.


Solution

  • try with this (ValidatorFn):

    titleFormControl = new FormControl('', {
    validators: [
      Validators.required,
      Validators.minLength(4),
      this.isNameDuplicate.bind(this) // <----- Custom validator method call
    ],
    });
    
    
     isNameDuplicate(control: AbstractControl): { [key: string]: boolean } | null {
     const ret = this.data.findIndex((item, index) => index !== this.selSheetIndex && item.id >= 0 && this.titleFormControl.value === item.title) >= 0;
     if (ret) {
      return { duplicate: true };
     }
    }
    

    in html

     <mat-error *ngIf="titleFormControl.hasError('duplicate')">
      Name already used
    </mat-error>