ngx-datatable icon indicating copy to clipboard operation
ngx-datatable copied to clipboard

ExpressionChangedAfterItHasBeenCheckedError

Open BotanMan opened this issue 7 years ago • 41 comments

[x] bug report => search github for a similar issue or PR before submitting [ ] feature request [ ] support request => Please do not submit support request here, post on Stackoverflow or Gitter

Current behavior It's looks like it relates to other library, but it's interferes with ngx-datatable, at least I reproduced in that connection

When I show modal window from ng-bootstrap by handling (select) output I get ng:///NgxDatatableModule/DataTableBodyRowComponent.ngfactory.js:12 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'datatable-body-cell sort-active active'. Current value: 'datatable-body-cell sort-active'.

it works fine when I show the same modal by (click) on some button on the page, but it raise each time I do that by (select), and when it happens, next modal activate break the page

Reproducing Fully reproduced with last angular and both packages here http://plnkr.co/edit/Ru8xoU3PNOqu4S1qUfbn?p=preview

BotanMan avatar Apr 28 '17 12:04 BotanMan

Intersting, but in case I put some button in column

 <ngx-datatable-column name="Registration Date"
                                prop="registrationDate"
                                [resizeable]="false"
                                [flexGrow]="1">
            <ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
              <button
                  class="btn-primary btn"
                  (click)="emptyClickHandler()">Edit</button>
            </ng-template>
          </ngx-datatable-column>

So I have both (activate)="click()" as table component input and (click)="emptyClickHandler()" as button (click) input

there are no error.

BotanMan avatar Apr 28 '17 12:04 BotanMan

Getting the same error in a similar situation: instead of bringing up the dialog when the row is selected, I have a column that shows an icon (just a span) which has a click event handler to bring up the ng-bootstrap dialog. If I put the click handler on a button instead of the icon, it works.

dae721 avatar May 01 '17 19:05 dae721

Hello, do we have any updates regarding this issue?

andrii-oleksyshyn avatar Jun 22 '17 12:06 andrii-oleksyshyn

Exact same situation as @BotanMan . Trying to open BootstrapModal with dyn. component only that I'm using (active) not (select) to fire the modal. But exact same Error.

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'datatable-body-cell sort-active active'. Current value: 'datatable-body-cell sort-active'.

any news? @amcdnl ?

faxemaxee avatar Jul 20 '17 11:07 faxemaxee

Same issue I am facing that when i click on my icon in ngx-datatable column open modal it works fine but showing same error in my console.

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'datatable-body-cell sort-active active'. Current value: 'datatable-body-cell sort-active'.

Do we have any updates regarding this issue?

himanshu-khurana avatar Jul 21 '17 06:07 himanshu-khurana

Any updates to this issue i am getting the same error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'datatable-body-cell sort-active active'. Current value: 'datatable-body-cell sort-active'.

SnakeB avatar Aug 02 '17 10:08 SnakeB

Is it related to https://github.com/angular/angular/issues/17572 by any chance?

maxtacco avatar Aug 02 '17 10:08 maxtacco

I am still facing the issue. If i got a solution i comment on git hub in this topic

On Wed, Aug 2, 2017 at 3:47 PM, Max [email protected] wrote:

Is it related to angular/angular#17572 https://github.com/angular/angular/issues/17572 by any chance?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/swimlane/ngx-datatable/issues/721#issuecomment-319631345, or mute the thread https://github.com/notifications/unsubscribe-auth/AO5u-SfZkasULbqWGBE_N8mGFySLstN2ks5sUEyygaJpZM4NLbKd .

-- Thanks & Regards

[image: Oodles Technologies Pvt Ltd] http://www.oodlestechnologies.com/

Himanshu Khurana Assistant Consultant-UI, Oodles Technologies Pvt Ltd Phone: +91 124 4368 395 Mobile: +91 9899442240 Email: [email protected] [email protected] Website: http://www.oodlestechnologies.com/ Skype: himanshukhurana.oodles

[image: Twitter] https://twitter.com/oodlestech [image: Facebook] https://www.facebook.com/OodlesTech [image: Google +] https://plus.google.com/+Oodlestechnologies/posts [image: LinkedIn] https://www.linkedin.com/company/oodles-technologies-pvt-ltd

himanshu-khurana avatar Aug 02 '17 10:08 himanshu-khurana

I'm not very proud of this solution, but the only way I got it to work is by blurring the datatable-body-cell right before emptyClickHandler main logic. We can target it by passing a reference to the template element and then looking up the parent of the parent (btnElement.parentElement.parentElement)

Something like this:

HTML:

<ngx-datatable-column name="Registration Date"
                         prop="registrationDate"
                         [resizeable]="false"
                         [flexGrow]="1">
       <ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
       <button #btnElement
             class="btn-primary btn"
             (click)="emptyClickHandler(btnElement)">Edit</button>
       </ng-template>
</ngx-datatable-column>

JS:

emptyClickHandler(btnElement) {
     btnElement && btnElement.parentElement && btnElement.parentElement.parentElement &&
         btnElement.parentElement.parentElement.blur();

// ... Other logic here .. say to open a modal window

}

torontocode avatar Aug 25 '17 19:08 torontocode

I think this error is causing by the cell is deactive by popping up a modal, since it loses focus. The problem is the table component has been checked by angular and now it is changed by the modal. Therefore, it throws an error like ExpressionChangedAfterItHasBeenCheckedError.

To prevent this error, I think the best way is preventing the cell become active or as soon as it becomes active, deactivate it.

onActive(event) {
        (event.type === 'click') && event.cellElement.blur();
}

maxisam avatar Aug 27 '17 05:08 maxisam

I couldn't get this to work @maxisam. Your solution relies on event bubbling which makes its reponse too late - the error has already happened. Shame because I thought it looked like a more elegant solution.

torontocode avatar Aug 28 '17 13:08 torontocode

@torontocode http://plnkr.co/edit/y2rPVs32V09nSEuffD3W?p=preview

maxisam avatar Aug 28 '17 16:08 maxisam

For the timebeing I wrapped the code at which this occurs in a setTimeout.

setTimeout(() => {
    //Code that triggers the error
})

ScottSpittle avatar Aug 29 '17 04:08 ScottSpittle

Our case called for something a little different (because we needed to call event.stopPropagation() to prevent selection (onSelect) of the row (so @torontocode 's solution worked).

component.ts

...
public deleteField(event: any, row: any, firstChild: any): void {
    event.stopPropagation();
    firstChild && firstChild.parentElement && firstChild.parentElement.parentElement &&
      firstChild.parentElement.parentElement.blur();
    // open delete modal
    this.modalService.open(DeleteComponent);
    ...
}

public onSelect($event): void {
    // navigate to details page
}
...

component.html

<ngx-datatable-column>
  <ng-template ngx-datatable-cell-template let-row="row">
    <div #firstChild>
      <div (click)="deleteField($event, row, firstChild)" class="field-delete text-center">
        <i class="fa fa-trash"></i>
      </div>
    </div>
  </ng-template>
</ngx-datatable-column>

Does anyone know if there's a better way to do this so that we could use the onActive method (bypassing the onSelect) ?

zoubarevm avatar Aug 31 '17 13:08 zoubarevm

As @maxisam noted, calling event.cellElement.blur() from (activate) works for me.

component.html

<ngx-datatable
    #datatable
    class="custom"
    [columns]="columns"
    [rows]="rows"
    [selected]="selected"
    [loadingIndicator]="loadingIndicator"
    [columnMode]="'force'"
    [headerHeight]="40"
    [footerHeight]="0"
    [rowHeight]="'auto'"
    [reorderable]="false"
    [sortType]="'single'"
    [selectionType]="'single'"
    [selectCheck]="singleSelectCheck"
    (activate)="onActivate($event)">
</ngx-datatable>

component.ts

onActivate(event: any) {
    if (event.type === 'dblclick') {
        event.cellElement.blur();
        this.edit(event); 
    }
}

maxtacco avatar Sep 07 '17 15:09 maxtacco

Same issue. I had to use both the onActivate from @maxtacco and @maxisam and the setTimeout from @ScottSpittle to get rid of the error. Neither worked for me by themselves.

bweeres avatar Sep 07 '17 21:09 bweeres

Call event.cellElement.blur(); when click worked for me 👍

hvqthong avatar Sep 25 '17 03:09 hvqthong

I am reporting that I am also experiencing this issue.

using I have cells that sometimes have a button that opens a model using ngBootstrap to show some data and this change detection error occurs each time the modal opens.

@maxisam - I was able to clear the error with your suggestion, thank you! Hopefully there will be some fix for this in the core library and I can remove this hack or find a better way around this without having to subscribe to activate(), as I do not need it for any other prupose

paustint avatar Oct 31 '17 03:10 paustint

Error happens for us, it indicates that ngx-datatable is violating Angular's one way data flow. In development mode and non-AOT production builds luckily the only bad effect is the warning. With an AOT compiled build you get data synchronocity issues 😒

insidewhy avatar Nov 03 '17 12:11 insidewhy

@maxtacco is this event only work for active? why the click event doesn't have the cellElement property?

needforspeed avatar Nov 15 '17 18:11 needforspeed

@needforspeed I needed that for double click, but as @maxisam showed it should work for single click as well.

maxtacco avatar Nov 15 '17 18:11 maxtacco

Anyone managed to fix this?

xyrintech avatar Dec 22 '17 16:12 xyrintech

No solution seems to be working.

xyrintech avatar Dec 22 '17 16:12 xyrintech

@xyrintech you could wrap ngx-datatables in an ng-container and use an *ngIf="...; let ..." over your stream. That's what I did anyway. Works around the bug.

insidewhy avatar Dec 27 '17 20:12 insidewhy

I understand, may I have the sample code for this?

xyrintech avatar Dec 28 '17 04:12 xyrintech

<ng-container *ngIf="stream$ | async; let value"> then use the resolved value instead of stream$. No empty stream no troubles.

insidewhy avatar Dec 28 '17 11:12 insidewhy

Any updates on this? We are running into the same issue...

anx-ckreuzberger avatar May 09 '18 14:05 anx-ckreuzberger

I encountered this same issue today

swseverance avatar May 11 '18 16:05 swseverance

I also encounter this problem today. I had to implement the workaround as others have mentioned above. My template:

                              prop="job_id"
                              [width]="80"
                              [sortable]="false">
            <ng-template let-row="row" ngx-datatable-cell-template>
                <span class="btn-link fake-link" (click)="getTranLog(row.job_id, $event)">{{row.job_id}}</span>
            </ng-template>
        </ngx-datatable-column>

And in my component:

		event.target.parentElement.parentElement.blur();
		this.modalRef                         = this._modalSvc.open(TranLogModalComponent);
		this.modalRef.componentInstance.jobID = jobID;
	}``` 

jessicahur avatar May 16 '18 19:05 jessicahur

Same problem, resolved with blur...

event.target.closest('datatable-body-cell').blur();

XciD avatar May 22 '18 13:05 XciD