Error causing expression change after Angular binding has been checked

Take a look at this demo:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h1>{{ foo }}</h1>    
      <bpp [(foo)]="foo"></bpp>
    </div>
  `,
})
export class App {
  foo;
}

@Component({
  selector: 'bpp',
  template: `
    <div>
      <h2>{{ foo }}</h2>
    </div>
  `,
})
export class Bpp {
  @Input('foo') foo;

  @Output('fooChange') fooChange = new EventEmitter();

  ngAfterViewInit() {
    const possiblyAsyncObservable = Observable.of(null);

    possiblyAsyncObservable.subscribe(()=> {
      this.fooChange.emit('foo');
    })
  }
}

There's an occasional error that pops up:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'foo'

This error occurs because the two-way binding is updated by an observable that can return a value in the same tick. I'd rather not use a setTimeout workaround as it seems like a hack and complicates the logic.

How can we prevent this error from happening?

Is the

ExpressionChangedAfterItHasBeenCheckedError
error harmless or should we address it? If we should, is there a way to ignore it and prevent console clutter?

Answer №1

To begin, let's simplify the explanation by breaking down the two-way data binding:

<div>
  <h1>{{ foo }}</h1>    
  <bpp [foo]="foo" (fooChange)="foo=$event"></bpp>
</div>

Even with this simplified version, the error can still occur under certain conditions, particularly when the

potentiallyButNotNecessarilyAsyncObservable
is synchronous. In such cases, we can opt for a more straightforward approach like so:

ngAfterViewInit() {
    this.fooChange.emit('foo');

This scenario falls into the realm of "Synchronous event broadcasting" errors as outlined in the article discussing the

ExpressionChangedAfterItHasBeenCheckedError
error.

The ngAfterViewInit hook triggers after the parent component's changes have been processed. The order of hooks concerning child components is detailed in the article on change detection in Angular. This issue arises from Angular retaining the initial value of foo during change detection for the App component, which clashes with the updated value passed on by the child Bpp component.

How can we prevent this error?

Solutions and potential pitfalls are thoroughly discussed in the linked article. In this context, opting for asynchronous updates seems to be the safest bet without resorting to a complete logic overhaul. Although triggering parent component change detection might seem viable, it could potentially spiral into an infinite loop as it cascades through the children components.

Is the ExpressionChangedAfterItHasBeenCheckedError consequential or dismissible?

In practical terms, this error leads to inconsistencies between the application state (App.foo==='foo') and the view representation ({{foo}}===undefined) until the next digest cycle. While the error persists in development mode, it remains dormant in the production environment.

For further insights, Two Phases of Angular Applications offers a valuable perspective on navigating through this type of error.

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

Ion-footer positioned above keyboard

I have been struggling with a persistent issue and have attempted numerous solutions to resolve it, but the problem persists. When using the web app on Google browser with my phone, I encounter an issue where the footer overlaps with the keyboard. Has anyo ...

Deactivate the FormGroup by implementing Validators

In my form, I have a checkbox group named formArray within my checkboxForm. The task at hand is to disable the submit button if none of the checkboxes are checked. To achieve this, I created a custom validator for my checkboxForm and here is my approach: ...

Create a function that can accept either no parameters or one parameter depending on the input parameter provided

Do you think there is a more efficient way to write this code? The function Z can be called with either one parameter or with no parameters. If the parameter Y is passed in, then the function z(y) is returned, otherwise just run the function z() async x ...

Retrieve external JSON using Ionic

Currently, I am facing a challenge with Ionic 5 as I am trying to retrieve data from a remote server in JSON format through a REST service. To accomplish this task, I have created a service provider and utilized the httpClient get method to fetch the JSON ...

The data type 'AbstractControl | null' cannot be assigned to type 'FormGroup'

I am facing an issue with passing the [formGroup] to child components in Angular. The error message says Type 'AbstractControl | null' is not assignable to type 'FormGroup'. I have double-checked my conditions and initialization, but I ...

Ways to detect duplicate entries while submitting a form and sending an error message back to the front-end

I am currently working on a project that involves a Spring-boot back-end restful service serving an Angular client. The issue I am facing is related to submitting user-group data with unique codes from a form, but duplicates are being stored in the databas ...

Learn the process of programmatically inserting mat-expansion panels

I need help dynamically adding mat-expansion-panel components to my project. Ideally, I would like to add them when a user triggers a function by clicking a button. The ability to add multiple expansion panels as needed is crucial. My initial attempt invo ...

Storing and retrieving user credentials across different applications using NativeScript and Angular 2

I am looking to store user credentials (username and password) in a Nativescript application. In another Nativescript application, I need to be able to retrieve these stored credentials. Unfortunately, I am unsure of how to accomplish this in Nativescript ...

What is the best way to add a 'Drawer' component into the 'AppBar' using React MUI within the Next.js framework?

My goal is to create an App bar with a 'hamburger' icon on the left that, when clicked, will display a Sidenav (drawer). I am working with React Material and Next.js (App router) and need to have the app bar and drawer as separate components, hea ...

An issue has been identified with React's HTML input maxLength feature where it does not display an error

Within my form, I have an input field that currently does not include validation for a maximum length. <input type="text" className="form-control" id="company" onBlur= ...

Styling can be compromised by Angular due to selector element interference

I have a question regarding a bootstrap button group. The buttons within it are Angular components structured like this: <div class="btn-group float-right" role="group" aria-label="Basic example"> <app-action [actionType]="'inv ...

Unexpected behavior encountered when using TypeScript type declarations

I am currently working on a Gatsby side project incorporating Typescript for the first time. I initially expected Typescript to behave similarly to PHP type declarations, but I have encountered some unforeseen issues. Despite feeling confident in my Typesc ...

Enhance Tuple in Angular Component Properties

When using React, state variables can be created like this: const SomeComponent = ({ someProp }) => { const [value, setValue] = useState<boolean>(false); } I wonder if there is a similar way to achieve the spread of a tuple within an Angular co ...

After installing TypeScript community stubs, WebStorm is unable to locate the module

Recently, I tried to incorporate the ramda library into my project and went ahead to install its TypeScript community stubs in WebStorm. https://i.stack.imgur.com/fCFG8.png Despite my efforts, I encountered an error that stated — Cannot find module &a ...

Verify the completeness of data types within an array in typescript

I am currently developing a comprehensive match function that I want to ensure is exhaustive during compile time. Although adding a default case would help with this, I am intrigued by some interesting dependent typing techniques I have come across. It wou ...

Trouble with yarn not functioning properly when using a Nexus 3 npm proxy repository

I have configured a Nexus 3 Manager to serve as a host for private npm packages. Within the nexus are three npm repositories: one labeled hosted, another as proxy, and a third named group which combines the former two. The npm bearer realm has been activat ...

Angular 8 - Generating Lists from POST Request Responses in JSON Format

My goal is simple: -extract the "monthYear" from the JSON response and assign them to a variable list called xValues -extract the "numSessionIds" from the JSON response and assign them to a variable list called yValues The JSON response data is as fo ...

How to focus on an input element in Angular 2/4

Is there a way to focus on an input element using the (click) event? I'm attempting to achieve this with the following code, but it seems like there may be something missing. (I am new to Angular) sTbState: string = 'invisible'; private ele ...

What is the best way to filter specific data types when using ngFor in Angular?

As I loop through the array named "fruits," which contains objects of type "FruitService" that I created, I want to display each element. However, when I delete them (I know it's strange, no database involved), they turn into type "undefined" and star ...

Setting up Typescript error handling for next-auth getProviders configuration

I recently started learning Typescript and came across a tutorial using next-auth. However, I encountered an error while following the tutorial with Typescript when using the getProviders function. https://i.stack.imgur.com/H5LaL.png https://i.stack.imgu ...