Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked

I have a dialog form that allows users to add a new project. I am trying to disable the save buttons until the form is valid (all required fields are filled in correctly). I have an isValid() function that is accomplishing this and everything seems to work fine. However, when viewing the console, I am getting the following message:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous 
value: 'mat-form-field-should-float: false'. Current value: 'mat-form-field-should-float: true'.

The mat-form-field is here:

                <mat-form-field class="input-half-width">
                    <input matInput [formControl]="name" placeholder="Project Name" #nameInput required> 
                </mat-form-field>

I have narrowed it down to the following html that is causing the error. If I remove [disabled]=!isValid(), this error goes away. However, I need this validation so removing it is not an option.

            <button mat-raised-button (click)="closeDialog(saveAndContinueIsClicked);">Close</button>
            <button mat-raised-button color="primary" [disabled]="buttonIsClicked || !isValid()" (click)="saveAndCloseDialog(false); buttonIsClicked=true; saveAndContinueIsClicked=true;">Save and Continue</button>
            <button mat-raised-button color="primary" [disabled]="buttonIsClicked || !isValid()" (click)="saveAndCloseDialog(); buttonIsClicked=true;">Save and Close</button>

The isValid() function is as follows:

  isValid() {
    if (this.projectName.value == null || this.projectName.value == "") {
        this.error = 'Name is required';
        this.nameElement.nativeElement.focus(); // If I comment this line out, the error goes away.
        return false;
    }

And in my component, nameElement is defined here:

@ViewChild('nameInput')
nameElement: any;

I have a general idea on why this is happening. When the focus is set to the name field and the dialog is opened, the name field is focused on, causing the label to float. I may just remove the line that focuses on the name input but would rather not if there is a way around this.

like image 499
BenTen Avatar asked Oct 18 '25 12:10

BenTen


2 Answers

Step 1

Add to the relevant module:

import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';

  providers: [
  // ...,
   {
      provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
      useValue: { floatLabel: 'always' },
    },
  // ...
  ],   

Step 2

Add to the relevant component:

export class MyComponentWithConsoleError implements OnInit, AfterContentChecked {
  ngOnInit(): void {
    // ...
    this.cd.detach();
  }
  
   ngAfterContentChecked(): void {
    this.cd.detectChanges();
  }
  
}

For me, the solution was adding this:

  ngAfterContentChecked(): void {
    this.cdr.detectChanges();
  }

To my dialog component. Hope it can be of use to someone else as well.

And don't forget to add ChangeDetectorRef to the constuctor.

  constructor(
    private readonly dialogRef: MatDialogRef<MyRandomModalComponent>,
    private cdr: ChangeDetectorRef, # <--- this line.
  ) {}
like image 39
Oushima Avatar answered Oct 20 '25 01:10

Oushima