Encountering ExpressionChangedAfterItHasBeenCheckedError in Angular 17 even after invoking detectChanges method

I'm encountering a minor problem with Angular and its change detection mechanism. I have created a simple form where additional input fields can be added dynamically. However, every time I click the add button, an

ExpressionChangedAfterItHasBeenCheckedError
is thrown in the console. When I use a regular ngFor loop, the error appears in the console but the new input field is still displayed. On the other hand, when I utilize Angular's new @for directive, the error shows up in the console and the new input field does not appear on the screen. I have tried calling both detectChanges and markForCheck, but it did not resolve the issue.

public properties: Map<number, string> = new Map<number, string>();

public addProperty() {
  const id: number = this.properties.size ?
    Array.from(this.properties.keys()).reduce((a, b) => a > b ? a : b) + 1 : 1;

  this.properties.set(id, 'placeholder');
  this.changeDetectorRef.detectChanges();
}
<button class="btn btn-primary" (click)="addProperty()">+</button>

<div class="d-flex flex-column">
  <ng-container *ngFor="let attribute of properties.entries()">
    <span>{{ attribute[0] }}</span>
  </ng-container>
</div>

Any help to address this issue would be highly appreciated. Thank you in advance.

I have experimented with both ngFor and Angular's new @for, and found that the main difference is that the data added using @for is not displayed along with the console error. I also attempted manual change detection without success.

Answer №1

Angular's ngFor functionality is specifically tailored for arrays, which can sometimes cause confusion with change detection when dealing with references in maps. A simple solution is to convert the map into an array before passing it to ngFor, effectively resolving any potential change detection issues. Below is a functional example:

If you only need the keys or values, you can access them using properties.keys() or properties.values() respectively.

import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule],
  template: `
    <button class="btn btn-primary" (click)="addProperty()">+</button>
    <div class="d-flex flex-column">
      {{properties.entries() | json}}
      <ng-container *ngFor="let attribute of mapEntriesToArray;trackBy: trackByFn ">
        <span>{{ attribute[0] }}</span>
      </ng-container>
    </div>
  `,
})
export class App {
  public properties: Map<number, string> = new Map<number, string>();

  constructor(private changeDetectorRef: ChangeDetectorRef) {}

  get mapEntriesToArray() {
    return Array.from(this.properties.entries());
  }

  public addProperty() {
    const id: number = this.properties.size
      ? Array.from(this.properties.keys()).reduce((a, b) => (a > b ? a : b)) + 1
      : 1;

    this.properties.set(id, 'placeholder');
  }

  trackByFn(index: number, item: any) {
    return index;
  }
}

bootstrapApplication(App);

Check out the live demo on stackblitz

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

Creating HTML code using an array of objects

My goal is to create HTML tags based on the object response shown below: "view": [{ "type": 'text', "depth": 0, "text": "This is a sample text" }] The objective here is to iterate through each type and add the corresponding HTML tags. &l ...

Authentication is needed when accessing ASP.NET Core 3.1 Angular with Windows. Please provide your username and

I am currently working with ASP.NET Core 3.1 and Angular. I am looking to integrate Windows authentication along with JWT for canActivate in Angular during routing, and also authorize the controller. However, I always get prompted for the Windows username ...

Angular service encountering duplicated arrays when retrieving data from Firebase using HTTP.get

While working on my Angular web application, I encountered a strange issue with duplicate arrays in the response from an HTTP get call to a Firebase realtime database. The Firebase setup includes a realtime database configured like this: Firebase data I ...

User interaction with a checkbox triggers a state change in Angular

Here is the code snippet I am working with, where clicking should set the checked value to false: @Component({ template: ` <input type="checkbox" [checked]="checked" (change)="onChange()"> ` }) export class AppC ...

Using the typescript infer feature does not function properly when dealing with arrays

My TypeScript code is causing some unexpected results: const myObject = { foo: ['a', 'b', 'c'] } type MyType = typeof myObject.foo extends [...infer Content] ? string : boolean The type MyType is coming out as 'string ...

How to programmatically close a ngbDatePicker popup in Angular using TypeScript

I am currently working with Angular 9 and Ng-Bootstrap, encountering an issue with my ngb-datepicker. I have implemented a Range datepicker in a popup and would like it to close automatically when a range is selected. The problem arises because I want to ...

Angular2 and the exciting world of Mapbox-gl

I am currently facing an issue with integrating mapbox-gl into my Angular2 application. Despite creating the service, the app is not functioning properly. Service import {Injectable} from '@angular/core'; import * as mapboxgl from 'map ...

The Hapi response fails to display JSON data in a nested tree format

Hey there! I've got this object with a specific structure. Here it is: interface FolderWithContent { uuid: string name: string; folders: Array<FolderWithContent>; files: Array<Files>; } Just a heads up, Files is an extens ...

"Encountered a 'NextAuth expression cannot be called' error

Recently, I delved into learning about authentication in Next.js using next-auth. Following the documentation diligently, I ended up with my app/api/auth/[...nextauth]/route.ts code snippet below: import NextAuth, { type NextAuthOptions } from "next-a ...

The reloading feature in Angular components is not functioning as intended

I am looking for a way to refresh the component without having to refresh the entire page. Below is the code snippet that I have been using: import { Component, VERSION, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from &apos ...

Implementing dynamic styles for a checked mat-button-toggle in Angular 6

How can I customize my button-toggle when it is checked? The current code I have doesn't seem to be working... This is the code snippet: <mat-button-toggle-group #mytoggle (change)="selectoption($event)" value="{{num}}"> <mat-bu ...

Error: The next.config.js file contains invalid options - The root value includes an unexpected property

I recently updated my next version from 10 to 12, and when I run the local development server, I encounter the following error in the terminal. As a result, the code fails to compile. How can I fix this issue? Invalid next.config.js options have been iden ...

I am a beginner in the world of Typescript/Angular, and I have encountered a compiling error TS2339. It seems that even when the condition *ngIf="x.length > 0;" should be false, the

I'm currently enrolled in a Typescript/Angular course where I am learning about the implementation of "*ngIf". During one of the lessons, the instructor provided an example using an empty array to demonstrate how it fails the condition and results in ...

Develop a module using the Angular plugin within the Eclipse IDE

I am currently new to Angular and following the Angular Get Started Tutorial (https://angular.io/guide/quickstart). I am using the angular cli plugin in Eclipse. As I reached the 7th part of the tutorial, I am required to create a new module with the comm ...

Access exclusive content by subscribing now!

How can I return a reference to a subject from a service without allowing the receiver to call .next() on the subject? Let's say there is a service with a subject that triggers new events. class ExampleService { private exampleSubject = new Subjec ...

What is the best method for inserting a hyperlink into the JSON string obtained from a subreddit?

const allowedPosts = body.data.children.filter((post: { data: { over_18: any; }; }) => !post.data.over_18); if (!allowedPosts.length) return message.channel.send('It seems we are out of fresh memes!, Try again later.'); const randomInd ...

Incorporate JavaScript Library into StencilJs Using TypeScript

Recently, I decided to incorporate a JavaScript library called Particles.js into my project. The process involved importing it and initializing it within my component: import { Component, h } from '@stencil/core'; import * as particlesJS from &a ...

Exploring Rxjs repeatwhen with a delay in action

I'm struggling to understand how repeatWhen and delay() work together. If you want to see my issue in action, click on this link and make sure to open the console. I tried using takeWhile to stop the repeatWhen stream before it gets to the delay ope ...

What is the best way to keep track of a checkbox's value after unchecking it and then returning to the same slide?

Issue: By default, the checkbox is always set to true in the backend code. Even if I uncheck it using JavaScript, the value remains as true when switching between slides. Desired Outcome: If I uncheck the checkbox, the updated value should be saved so tha ...

Is there a way to restrict an array to only accept distinct string literals?

export interface IGUser { biography: string; id: string; ig_id: string; followers_count: number; follows_count: number; media_count: number; name: string; profile_picture_url: string; shopping_product_tag_eligibility: boolean; username: ...