Search code examples
angularangular-ng-if

Angular *ngIf not updated with component method


When using a function to show/hide with *ngIf the block is not updated in the html. when rendering the block to check the value ({{contactInfoValid(contact)}}) it is updated correctly, the *ngIf is not being triggered

HTML

<mat-form-field>
            <input matInput  type="text"
                      [(ngModel)]="contact.info" required>               
            <mat-error *ngIf="contactInfoValid(contact) == false">
               email not correct
            </mat-error>
        </mat-form-field>

Component

  contactInfoValid(contact) {
    if (contact.hasValidInfo) {
       return true;
       }

    return false;
  }

The mat-error is never shown.

A FormControl cannot be used in this specific case since it is used in a dynamic grid


Solution

  • The <mat-error> component need an ErrorStateMatcher in order to display anything. There's a good article about this here; https://itnext.io/materror-cross-field-validators-in-angular-material-7-97053b2ed0cf

    In short you need to specify [errorStateMatcher]="myErrorStateMatcher" on the form field that you're validating.

    <mat-form-field>
       <input matInput type="text" [(ngModel)]="contact.info" required
            [errorStateMatcher]="myErrorStateMatcher">
       <mat-error *ngIf="contactInfoValid(contact) == false">
           email not correct
       </mat-error>
    </mat-form-field>
    

    Normally ErrorStateMatcher works with FormControls, but if you want to use ngModel you can provide custom ErrorStateMatcher that have access to the data you need in order to display error messages. Below is a simplified example of this;

    export class RuleErrorStateMatcher<T> implements ErrorStateMatcher {
        constructor(private editControl: IValidatableEditControl<T>) { }
    
        isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
            return this.editControl && this.editControl.model && !this.editControl.model.isValid;
        }
    }
    
    export interface IValidatableEditControl<T> {
        model: ValidationGeneric<T>;
    }
    
    export class ValidationGeneric<T>   {
        public value: T;
        public isValid: boolean;
    }
    
    

    If you try another html tag than mat-error you will see that your ngIf is probably working;

    <span *ngIf="contactInfoValid(contact) == false">
            email not correct
    </span>