Angular 4: The dreaded `ExpressionChangedAfterItHasBeenCheckedError` rears its ugly head, indicating that an expression has mutated

I am encountering an issue with every EventEmitter in my child module and despite trying, I cannot seem to find a solution for it.

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.

The code that is triggering my EventEmitter looks like this:

ngOnChanges(changes: any) {
    if (changes.groupingTabValid) {
        if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
            this.groupingTabValidChange.emit(this.groupingTabValid);
        }
    }
}

This is the HTML snippet of my "main" component:

<year-overview-grouping [definitionDetails]="definitionDetails"
                        [fixedData]="fixedData"
                        [showValidation]="showValidation"
                        [groupingTabValid]="groupingTabValid"
                        (groupingTabValidChange)="setValidators('groupingTab', $event)">

</year-overview-grouping>

Which then triggers this function:

public setValidators(validator: string, e: boolean) {
    switch (validator) {
        case "groupingTab":             
            this.groupingTabValid = e;
            break;

        case "selectionTab":
            this.selectionTabValid = e;
            break;
    }

    if (this.groupingTabValid && this.selectionTabValid) {
        this.valid = true;
    } else {
        this.valid = false;
    }
}

1) Can you explain simply what is causing this error?

2) What measures can be taken to resolve this issue?

Answer №1

Adhere to the one-way data flow principle

Consider delaying the emit function call by one tick using a setTimeout

if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
    setTimeout(() => this.groupingTabValidChange.emit(this.groupingTabValid), 0)
}

Answer №2

Simply include the ChangeDetectionStrategy module and insert this snippet into your component:

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-bla-bla-bla',
  templateUrl: './xxxxx'
})

Answer №3

To avoid using the setTimeout function, you can notify Angular that changes are imminent after the initial check.

You have the option to include the ChangeDetectorRef in your component and utilize its markForCheck method.

/* ... */

constructor(private cdr: ChangeDetectorRef) {}

/* ... */

if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue {
  this.cdr.markForCheck();
  this.groupingTabValidChange.emit(this.groupingTabValid);
}

Answer №4

As I delve into this particular exception type, it appears to serve the purpose of preventing feedback loops.

Upon closer examination, there doesn't seem to be a clear reason for passing the value down to the child and then back up to the parent. It is possible that the child component applies some additional logic, although in my opinion, it would be more appropriate to handle this logic within a service rather than a child component.

Although the provided plunker code does not include a loop, the Angular mechanism itself seems quite straightforward - simply rechecking values at the end of the cycle. It's worth noting that groupingTabValid in the given code enables direct feedback.

In terms of structural changes to the age parameter in the parent component, it can easily be managed within the parent. Utilizing a click event such as (click)=changeAge(age.value) and having a method (on the parent) like this:

changeAge(inputAge) {
  this.newAge = inputAge;
  this.person.age = inputAge;
}

For reference, here's a modified version of the plunker. You can find it here: Modified plunker
In this updated version, the child component still updates person.age, but without causing errors since the value remains consistent with what was set in the parent component.

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

When a user reverts UI changes to their original values in Angular reactive forms, does the pristine state reset?

I need the Submit button in my form to only be enabled when there is a change in the input. If the values in the form controls remain unchanged, the Submit button should be disabled. Initially, I attempted to utilize the FormGroup.pristine flag for toggl ...

Using two type arguments, create a feature selector with ngrx

Currently, I am delving into the world of ngrx with Angular v6.0.9 and AngularCLI v6.0.8. In an example application, there is a demonstration on creating a root level createFeatureSelector with two type arguments: example-app/app/reducers/index.ts ..... ...

Can someone explain the distinction between 'return item' and 'return true' when it comes to JavaScript array methods?

Forgive me for any errors in my query, as I am not very experienced in asking questions. I have encountered the following two scenarios :- const comment = comments.find(function (comment) { if (comment.id === 823423) { return t ...

Tips for implementing dependency injection with Dynamic Angular Components

I am currently working on creating a dynamic component within a container. I require access to predefined services and injections available in the Angular environment for this dynamically created component. The main reason for this is that there is an exte ...

Is it impossible to Build your Angular project?

After updating my current project from Bootstrap 4 to Bootstrap 5, I encountered an issue where Jenkins is unable to build the project. The error message displayed is quite cryptic: An unhandled exception occurred: Cannot destructure property 'bold&ap ...

Dealing with API Errors in Ngrx

I came across an interesting scenario in the ngrx example-app provided on Github. When starting a new project, I always strive to follow the best practices, so I referred to the example app for guidance. In one particular instance within the application, t ...

The NgRx Effect causing an endless cycle of HTTP requests

I am currently experiencing the following effect: initCompaniesAndSetCompanyEffect$: Observable<Action> = createEffect( (): Observable<Action> => this.actions$.pipe( ofType<changeCompanyActions.InitCompaniesAction>( ...

Angular component communication issue - emitter malfunctioning

Angular 4 Event emitter not functioning as expected despite following a tutorial for implementation. I am open to alternative solutions if available. Here is the code snippet for the transmitter component: .HTML <nav class="navbar navbar-toggleable-m ...

Utilize Angular 2 interceptor to incorporate HTTP requests

Dealing with the 401 response from an interceptor using the HttpClientModule in Angular and JWT authentication can be a bit tricky. When the accessToken expires, it's necessary to use the refreshToken to obtain a new one before making the actual API r ...

Encounter the issue of receiving 'undefined' as a response for data that was assigned within

Instead of calling the service in the .ts file and wasting time, I want to assign this as a global value that I can use. However, I keep getting undefined. Here is my service file @Injectable({ providedIn: 'root' }) export class DeService { ...

What is the procedure for setting up the typings folder in AngularJS 1.5 with TypeScript?

I'm currently working on a project using AngularJS 1.5 and TypeScript. I need to install the "angularjs/angular.d.ts" and "angularjs/angular-route.d.ts" files. Despite installing tsd globally, when I run the command "tsd install angular," I receive a ...

Unable to choose Typescript as a programming language on the VSCode platform

Recently, I encountered an issue while using Visual Studio Code with TypeScript. Even though TypeScript is installed globally, it is not showing up in the list of file languages for syntax highlighting. Despite trying various troubleshooting methods such a ...

Passing along the mouse event to the containing canvas element that utilizes chart.js

Recently, I created a custom tooltip for my chart.js chart by implementing a div that moves above the chart. While it works well, I noticed that the tooltip is capturing mouse events rather than propagating them to the parent element (the chart) for updati ...

Angular Recursive Bootstrap Breadcrumb Guide

I am looking to implement the bootstrap breadcrumb component (https://getbootstrap.com/docs/4.0/components/breadcrumb/) in my project. My goal is to use the breadcrumb to show the entire path to the current directory within a component that resembles a di ...

Retrieve the object attribute name through the request parameter in Express.js and Mongoose

Setting the Scene The issue at hand is my desire to access the attribute of an Object using the variable provided in the request. A GET /modify/:var request is initiated to alter the attribute of a saved document in MongoDB. In order to determine which at ...

Building a custom angular component library using the latest Angular CLI version 12

I attempted to create an angular workspace using Angular CLI with a library included. The goal was for another app to be able to import the angular npm package and display the exported default component. Here are the commands I used for generation: ng ne ...

Depend on a mapping function to assign a value to every option within a discriminated union

While utilizing all variations of a discriminated union with conditional if statements in TypeScript, the type is narrowed down to the specific variant. To achieve the same effect by expressing the logic through a mapping from the discriminant to a funct ...

Express throwing module errors

I encountered an issue while attempting to expose a REST service in an electron app using expressJS. Following a tutorial, I added express and @types/express to the project. However, when trying to implement a "get" method and running the build with ng bui ...

The concept of recursive generics in combination with array inference

I'm struggling to develop a couple of generic recursive types to adjust the structure of existing types. I can't figure out why the sections detecting arrays and nested objects are not being activated. Any thoughts on what might be going wrong? ...

Implementing authentication using http.post in Angular 2 with Django-Rest-Framework

I have spent more time than I care to admit trying to find a solution to this particular issue, but unfortunately, I am unable to resolve it on my own. Currently, I have a Django-rest-api that I set up using this tutorial. I can successfully interact with ...