Modified Expression Problem

Scenario :

On the left side of the screen, all unpaid bills are displayed. When a user clicks on a bill, its details appear on the right side. Upon clicking the pay button, the bill is marked as paid and should no longer be visible on the left side. This cycle continues for each bill.

Challenge :

I successfully paid a bill and it disappeared from the left side. However, when I attempt to click on the next bill on the left side, an error occurs.

Runtime Error ExpressionChangedAfterItHasBeenCheckedError: The expression has changed after being checked. Previous value: 'true'. Current value: 'false'.

Screencast :

https://i.sstatic.net/8SAbd.gif

Code :

bill-settlement.ts

@IonicPage()
@Component({
  selector: 'page-bill-settlement',
  templateUrl: 'bill-settlement.html',
})
export class BillSettlement {
  billItem: BillDetail
  updateItem: boolean
  ...
  onBillSelected(billData: BillDetail) {
    this.billItem = billData
  }
  isUpdate(updateData: boolean) {
    this.updateItem = updateData
  }
}

bill-settlement.html

...
<page-bill-list (BillSelected)="onBillSelected($event)" [updateItem]="updateItem"></page-bill-list>
...
<page-bill-details (isUpdate)="isUpdate($event)" [billItem]="billItem"></page-bill-details>

bill-list.ts

@IonicPage()
@Component({
  selector: 'page-bill-list',
  templateUrl: 'bill-list.html',
})
export class BillList {
  billItems: BillDetail[] = []
  billItem = new BillDetail()
  @Input() updateItem: boolean
  @Output() BillSelected: EventEmitter<BillDetail> = new EventEmitter<BillDetail>()
  constructor(...) {
    this.billSrv.getBills()
      .subscribe(data => {
        this.billItems = data
      })
  }
  ngOnChanges(updateItem: boolean) {
    if (this.updateItem == true) {
      this.billSrv.getBills()
        .subscribe(data => {
          this.billItems = data
        })
    }
  }
  getBillDetails(item: BillDetail) {
    this.BillSelected.emit(item)
  }
}

bill-list.html

<ion-buttons>
  <button ion-button *ngFor="let item of billItems" (click)="getBillDetails(item)">Bill {{item.BillNo}}</button>
</ion-buttons>

bill-details.ts

@IonicPage()
@Component({
  selector: 'page-bill-details',
  templateUrl: 'bill-details.html',
})
export class BillDetails {
  ...
  @Input() billItem: BillDetail
  @Output() isUpdate: EventEmitter<boolean> = new EventEmitter<boolean>()
  ...
  ngOnChanges(billItem: BillDetail) {
    this.isUpdate.emit(false) //if this part is commented
//the bills are paid but the left side is not reloaded from the second time
  }
  settleBill() {
    ...
    this.billSrv.settleBill(...).subscribe(
      data => {
        if (data) {
          this.isUpdate.emit(true) //so the bill list is reloaded
        }
        else {
          ...
        }
      }
    )
  }
}

Answer №1

Encounter with Runtime Error ExpressionChangedAfterItHasBeenCheckedError: The expression has altered after it was checked. Previously, the value was 'true', and now it is 'false'.

Usually, this error occurs during development (DEV) mode due to additional change detection cycles. It happens when a value changes between these extra cycles, indicating some instability in the data being updated. Ideally, values should remain stable until the next scheduled change detection cycle. The surplus cycles in DEV help identify unexpected value changes.

This situation often signals a problem in how component values are being managed, although there may be cases where the current behavior is intentional. To address this issue, you can resolve it by:

import { ChangeDetectorRef} from '@angular/core';

constructor(
    private cdr: ChangeDetectorRef
  ) { }

Subsequently, use this.cdr.detectChanges(); wherever a value change occurs that necessitates an additional round of change detection.

In essence, this error highlights instances where value changes could lead to issues in a Production environment, as they occur post the regular change detection cycle. Development mode initiates an extra round of change detection to identify such potential concerns.

For technical resolution, you might consider adding detectChanges following:

ngOnChanges(billItem: BillDetail) {
    this.isUpdate.emit(false) //if this part is commented
//the bills are paid but the left side is not reloaded from the second time
  }

The aforementioned adjustment would eliminate the problem; however, it may not be the preferred approach. When placing this.isUpdate.emit(false), keep in mind that it will trigger every time ngOnChanges or @Input() billItem: BillDetail changes. Thus, relocating this command to a more deliberate execution point might be advisable.

Answer №2

When encountering the error mentioned above, it is usually due to trying to modify a value that is being used during component creation. I faced this issue myself and made some changes that resolved the error. Hopefully, these solutions can help you too.

In my case, I needed to insert rows into a table with 2 columns - one for input and another for unit. After adding a row, the cursor should automatically focus on the INPUT field. By making the following code adjustments, the expression error disappeared:

Code:

ngAfterViewInit() {
       setTimeout (() => {
        if (!isNullOrUndefined(this.input.nativeElement)) {
          this.editingActive = true;
          this.input.nativeElement.focus();
          this.input.nativeElement.click();
              }
      }
    , 0);
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the process for dynamically setting a div element during runtime?

Is there a way to make a div element appear and disappear based on certain conditions? For instance, if the height of a previous div reaches a specific point, can we show a new div (2) element? And can it disappear when the div reaches its minimum height o ...

Automatically choosing the dropdown option using Ts functionality in Angular PrimeNG: A guide

<p-dropdown class="form-right-column mt-6" [options]="states" filterBy="name" [formControl]="$any(formGroup).get('state')" ...

What could be the reason for the failure of my class isInstance() check

Do you see any issues with the object being an instance of ChatRoom? Let me know your thoughts. Class: export class ChatRoom { public id?: number; public name_of_chat_room: string; public chat_creator_user_id: number; public chat_room_is_active: 0 ...

How to Resolve File Paths in CSS Using Angular 7 CLI

My assets folder contains an image named toolbar-bg.svg, and I am attempting to use it as the background image for an element. When I use background: url('assets/toolbar-bg.svg'), the build fails because postcss is unable to resolve the file. How ...

Angular 6 form controls with reactive elements

Looking to create a simple homepage using Angular 6. One of the features will include tests for prime factorization and leap years, implemented with reactive forms for validation. However, I am facing an issue where I cannot execute both functions simultan ...

Adding an asterisk to mark a required field in Angular reactive form inputs is a simple task that can be accomplished with just a

Currently, I am in the process of developing an application that utilizes a reactive dynamic angular form. The fields for this form are retrieved from an API request and generated dynamically. I have encountered the need to include a 'required field& ...

An easy way to insert a horizontal line between your text

Currently, I have two text responses from my backend and I'm considering how to format them as shown in the design below. Is it possible to automatically add a horizontal line to separate the texts if there are two or more broadcasts instead of displa ...

Oops! An unexpected error occurred: TypeError - Seems like _this.searchElementRef is not defined

I recently implemented the Google Place API in my project by following this tutorial. However, I encountered the following error: ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined The issue seems ...

When using Angular @NgModule imports, it is important to note that modules may not be recognized if the [].concat() method is

I am dealing with multiple modules and I need to organize and categorize them into different arrays based on their types const firstModules: any[] = [ Module1, Module2, Module3, Module4 ]; const secondModules: any[] = [ Module5, Module6, Mo ...

When you type a letter in the middle of a string, the cursor is automatically moved back to the end - Material UI

I designed a ChipInput feature that switches to a string when focused and transforms into a Chip component when blurred, with chips separated by commas. Everything seems to be functioning properly except for one issue I am encountering. Whenever I type in ...

How does the method of adding a class differ between *ngIf and [ngClass]?

Can you explain the distinction between code snippet 1 and code snippet 2? Snippet 1 <mat-sidenav *ngIf="menuClicked" class="col-3 pl-0" mode="side" fixedTopGap="56" opened="true"> <report-sid ...

Tips for implementing an 'exclude' feature in TypeScript without encountering any error notifications

export function omit<T, U extends keyof T>(obj: T, keys: U[]): Omit<T, U> { return Object.keys(obj).reduce( (acc, curr) => (keys.includes(curr as U) ? acc : { ...acc, [curr]: obj[curr] }), {} ) as Omit<T, U>; } Encounter ...

Using ngmodel in Angular to assign a value to the Angular Material datepicker

Having an issue with editing the selected value in a custom control value accessor for an Angular Material date component. The input field is returning empty. App.Component.Html <date-input ngModel="dateValue" name="dateName"> ...

Uncheck all boxes except for the required or disabled boxes in Angular

HTML: <mat-selection-list #selectedColumns [(ngModel)] ="selectedOptions"> <div class= "content-section"> <mat-expansion-panel> <mat-expansion-panel-header> ...

The app.component.ts file is not found in the project specified by tsconfig.json

Encountering an Error: An error occurred in File C:/wamp/www/angular2_demo/GiphySearch/src/app/app.component.ts stating that it is not part of the project defined by C:/wamp/www/angular2_demo/GiphySearch/e2e/tsconfig.json The current folder structure i ...

Angular 5: Steps to send an event from authguard to header in Angular application

I am struggling to send out an event from the authguard component to the header component. Event broadcasting setup @Injectable() export class BroadcastService { public subject = new Subject<any>(); sendMessage(message: string) { this.subjec ...

Guide to resolving a Promise that returns an array in TypeScript

My goal is to retrieve an array in the form of a promise. Initially, I unzipped a file and then parsed it using csv-parse. All the resulting objects are stored in an array which is later returned. Initially, when I tried returning without using a promise, ...

Service function in Angular 2 is returning an undefined value

There are two services in my project, namely AuthService and AuthRedirectService. The AuthService utilizes the Http service to fetch simple data {"status": 4} from the server and then returns the status number by calling response.json().status. On the ot ...

What steps should I take to create an Onboarding/Walkthrough page using Angular Material Design?

Looking for guidance on creating an Onboarding/Walkthrough in Angular Material Design for Electron. As a newcomer to Angular, I'm aiming for a desktop application similar to the image provided. It should showcase several images and offer page navigat ...

What is the process for initializing the default/prefilled value of an input element within a mat-form-field when the page loads?

I'm looking to create an HTML element where the default data (stored in the variable 'preselectedValue') is automatically filled into the input field when the component loads. The user should then be able to directly edit this search string. ...