rgoal
rgoal

Reputation: 1326

Angular ExpressionChangedAfterItHasBeenCheckedError with inline edit table

I have a table where it calls a child component called modal, modal component has two buttons save and cancel that are used for inline edit. I know I have to use "ChangeDetectorRef" but I cant figure out how to use the event "ngAfterViewInit" wit my code

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'disableEditSaveButton: false'. Current value: 'disableEditSaveButton: 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>
                                        <!--<button (click)="editRow(row)">Edit</button>-->
                                    </td>
                                    <td>                                <button (click)="save(row)">Save</button></td>
                                </tr>
                            </ng-template>

                    </p-table>

dashboard.compnent (this is causing ExpressionChangedAfterItHasBeenCheckedError)

 isEmpty(input) {
        if (input.replace(/\s/g, '') === "") {

            this.disableSaveButton = true;
        }
        else {
            this.disableSaveButton = false;
       }
       // this.cdr.detectChanges();

        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 browser it is still throwing ExpressionChangedAfterItHasBeenCheckedError

Component

   isEmpty(input) {

        this.cdr.detach();

        if (input.replace(/\s/g, '') === "") {

            this.disableSaveButton = true;
        }
        else {
            this.disableSaveButton = false;
        }
        // this.cdr.detectChanges();

        // restart change detection for this view
        this.cdr.reattach();

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

Upvotes: 0

Views: 865

Answers (2)

user6749601
user6749601

Reputation:

Okay, so here comes another approach.

Analysing your code I could see that

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

This means that, if isEmpty(row.comment) is true, this.disableSaveButton is true too and the other way round.

So why don't you directly use the result of isEmpty(row.comment) instead of storing it into this.disableSaveButton ? Doing this you have no changing expression as the first true or false will also be the last.

Please, try it this way:

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

And if you don't need this.disableSaveButton for other purposes than your modal dialogue, which means you don't need it at all now, you could shrink the size of your method to this, without changing it's logical outcome.

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

Upvotes: 1

user6749601
user6749601

Reputation:

Try it this way:

isEmpty(input) {
    // stop change detection for this view
    this.cdr.detach(); 

    if (input.replace(/\s/g, '') === "") {

        this.disableSaveButton = true;
    }
    else {
        this.disableSaveButton = false;
   }
   // this.cdr.detectChanges();

    // restart change detection for this view
    this.cdr.reattach(); 

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

Upvotes: 0

Related Questions