Error encountered when attempting to modify an Angular expression within a table that is being edited inline

In my table, there is a child component called modal which contains two buttons - save and cancel for inline editing. I am aware that I need to utilize "ChangeDetectorRef", but I am struggling to implement the event "ngAfterViewInit" in my code.

An error occurred: ExpressionChangedAfterItHasBeenCheckedError: The value of 'disableEditSaveButton' has changed after it was checked. Previous value: 'false'. Current value: 'true'.

dashboard.HTML

<p-table #dt [value]="iToDoList" dataKey="id" [paginator]="true" [rowsPerPageOptions]="[10,50,100]" [rows]="10">

    <ng-template pTemplate="header">
        <tr>
            <th>ID</th>
            <th>Comment</th>
            <th>Action</th>
        </tr>
    </ng-template>

    <ng-template pTemplate="body" let-row>  
        <tr>
            <td>{{row.id}}</td>
            <td>
                <div *ngIf="!row.isEditable">{{row.comment}}</div>
                <div *ngIf="row.isEditable">
                    <input type="text" [(ngModel)]="row.comment">
                    <span *ngIf="isEmpty(row.comment)" style="color:crimson">Required</span>
                </div>
            </td>
            <td>
                <div>
                    <modal [disableEditSaveButton]='disableSaveButton' (open)="onOpen(row)" [showModal]="!row.isEditable" (selectedRow)="onSelectedRow(row)" (cancelEdit)="onCancelEdit(row)"></modal>
                </div>
            </td>
            <td>
                <button (click)="save(row)">Save</button>
            </td>
        </tr>
    </ng-template>

</p-table>

dashboard.component (which is causing the ExpressionChangedAfterItHasBeenCheckedError)

isEmpty(input) {
    if (input.replace(/\s/g, '') === "") {
        this.disableSaveButton = true;
    } else {
        this.disableSaveButton = false;
    }

    return input.replace(/\s/g, '') === "";
}

modal.html

<div *ngIf='!showModal'>
    <button type="button" class="btn-xs btn-primary" (click)="onSave()" [disabled]='disableEditSaveButton'>Save</button>
    <button type="button" class="btn-xs btn-orange" (click)="onCancelEdit()">Cancel</button>
</div>

modal.component

@Input() disableEditSaveButton: boolean = false;

******************UPDATE*************************************************************************

The ExpressionChangedAfterItHasBeenCheckedError is still being thrown by the browser.

Component

isEmpty(input) {
    this.cdr.detach();
    
    if (input.replace(/\s/g, '') === "") {
        this.disableSaveButton = true;
    } else {
        this.disableSaveButton = false;
    }
    
    // restart change detection for this view
    this.cdr.reattach();

    return input.replace(/\s/g, '') === "";
}

Answer №1

Here is a new perspective to consider.

After reviewing your code, it is evident that

this.disableSaveButton === isEmpty(row.comment)

This indicates that when isEmpty(row.comment) is true, this.disableSaveButton is also true, and vice versa.

Instead of storing the result of isEmpty(row.comment) in this.disableSaveButton, why not directly use the result itself? This approach ensures consistency in the expression's evaluation.

I recommend trying the following:

<modal  [disableEditSaveButton]='isEmpty(row.comment)' 
        (open)="onOpen(row)" 
        [showModal]="!row.isEditable"  
        (selectedRow)="onSelectedRow(row)" 
        (cancelEdit)="onCancelEdit(row)">
</modal>

If you do not require this.disableSaveButton for any other purpose besides the modal dialogue, you can simplify your method as follows without altering its logical outcome.

isEmpty(input) {
    return input.replace(/\s/g, '') === "";
}

Answer №2

Here's a different approach to consider:

checkIfEmpty(input) {
    // pausing change detection for this component
    this.cdr.pause(); 

    if (input.replace(/\s/g, '') === "") {
        this.disableSubmission = true;
    }
    else {
        this.disableSubmission = false;
    }
    
    // resuming change detection for this component
    this.cdr.resume(); 

    return input.replace(/\s/g, '') === "";
}

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

Tips for conducting a worldwide search in Angular 2?

I'm currently navigating my way through angular2 development and I am aiming to conduct a comprehensive search within an array of JSON objects. To illustrate, consider this sample array: invoiceList = [ { invoiceNumber: 1234, invo ...

NextJS and AWS Amplify collaboration for secure authentication routing

After hours of research, I'm struggling to navigate the authentication routing in NextJS combined with AWS Amplify. As a newcomer to NextJS, I want to implement a feature that disables the login/register page for users who are already logged in and pr ...

Typescript: The original type cannot be indexed with a type-mapped type

I'm currently working on a class where I need to define a method that returns an object with keys based on the generic type inferred by the compiler. However, I've encountered an issue with the code snippet below. The compiler is indicating that ...

What is the best method to fill a mat-select dropdown with an existing value?

I am encountering an issue with a mat-form-field that contains a dropdown of data fetched from an API. I can successfully select an option and save it to the form. However, upon returning to the dropdown or reloading the page, the saved value does not appe ...

Redirect users in Angular 9 when query parameter is missing

When a user clicks a link from an email, they should be directed to a specific route only if the URL contains a valid query parameter. If the parameter is missing, I want to redirect them to a 404 page not found component as shown below. this.route.queryP ...

Tips for troubleshooting the error message: "The relative import path "$fresh/dev.ts" is not prefaced with / or ./ or ../"

My editor is showing a TypeScript error for a Deno module I am working on. The import path "$fresh/dev.ts" should be prefixed with / or ./ or ../ I have an import_map.json file set up with the following content. { "imports": { "$fre ...

Issue TS2322 presents itself when attempting to assign a value of type 'string, number, or Date' to a variable of type 'Date' after upgrading to Angular 16

I recently upgraded my project from Angular 11 to Angular 16 and encountered an issue with the DTO models generated using the NPM package "ng-swagger-gen" from the Swagger JSON file of the Web API. In my C# class on the Web API side, I have a DateTime fiel ...

Enhance your Angular app by dynamically adding classes to existing classes on a host component

How can I dynamically add a class to the host component of this angular component? @Component({ selector: 'test', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], encapsulation: ViewEncapsulation ...

What steps can I take to persistently subscribe to SignalR from an Angular service even in the event of connection failures?

Is there a way to safely attempt to connect to SignalR with intervals between attempts until the connection is established? Also, does anyone have advice on how to handle the different stages of connectivity to the web sockets effectively? We are utilizin ...

Is there a way to remove a button when it's clicked in Angular?

I have created a button component that is styled to resemble a pill for tab-focusability purposes. This button will be used to display keywords that a user searches for. I want the ability to remove or delete the displayed keyword by clicking on an X icon. ...

Challenges with npm installation in Angular Quickstart

I've been following the Angular getting started guide and encountered some issues. After cloning the repository, I attempted to run npm install, but I'm encountering errors: npm WARN package.json <a href="/cdn-cgi/l/email-protection" class=" ...

I am trying to replace the buttons with a dropdown menu for changing graphs, but unfortunately my function does not seem to work with the <select> element. It works perfectly fine with buttons though

I am currently working on my html and ts code, aiming to implement a dropdown feature for switching between different graphs via the chartType function. The issue I am facing is that an error keeps popping up stating that chartType is not recognized as a ...

Angular application enhanced with a Freshdesk feedback widget

I'm facing an issue while trying to integrate the Freshdesk feedback widget into my Angular application (version 8.2.7). I obtained the widget embed code from the Freshdesk admin portal. Below is the widget code snippet: <script> window.f ...

Encountering a problem when launching the "vite-express" template on the Remix app (TSConfckParseError: error resolving "extends")

I recently launched a brand-new [email protected] project using the remix-run/remix/templates/vite-express template after executing this command: npx create-remix@latest --template remix-run/remix/templates/vite-express However, upon trying to run th ...

Do not include ChangeDetectionStrategy when creating component

Is it possible to eliminate the default ChangeDetectionStrategy for each component creation? (Please note that I am working with Angular V 10 in a controlled environment for project maintenance) @Component({ xyz, changeDetection: ChangeDetectionStrategy. ...

Troubleshooting issue with beforeEach in karma and Mocha after upgrading to Angular 4

Unique Context After verifying the successful "green" builds on the master branch, which utilizes angular-cli 1.0.0 and the older angular2 dependencies, my goal is to transition from angular2 to angular4. Issue Post Upgrade The application functions pr ...

Angular2 - Integration and utilization of the datepicker component

Is there a way to retrieve the selected date from an input and wrap it in a <p> tag? I've been attempting to use the jQueryUI datepicker and have tried binding events like change and click, but haven't had any success. Can anyone offer som ...

Upon refreshing the Angular application in the browser, we received a response from Django

I am currently developing an application with a Django backend and an Angular frontend. Everything was working smoothly until I encountered an issue after refreshing a page in the browser. The Angular response stopped coming through, but I continued to rec ...

Modeling a potentially empty array in Typescript can be achieved by implementing specific interface definitions

Here is the current situation: type A = { b: string, c: number } I have an object that I will receive from an API, which could be either A[] or [] As of now, when I attempt to use it, const apiData: A[] || [] const b = apiData[0].a // I expected this to ...

Exploring the possibilities of ZMQ_XPUB_MANUAL in action with zeromq.js

I'm currently in the process of setting up a pub/sub broker using ZeroMQ, and I want to ensure that clients are only able to subscribe to authorized prefixes. While researching this topic, I came across a helpful tutorial that discusses achieving a si ...