0

I am using ngScrollReveal, which causes a re-render every scroll event. I am calling a function through the HTML like follows:

<component [alternate]="toggleAlternate()">

The definition of toggleAlternate() looks like:

toggleAlternate() {
  this.alternate = !this.alternate;
  return this.alternate;
}

However, I get the following error on every scroll event:

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

I have tried a couple of solutions such as injecting ChangeDetectorRef and calling detectChanges() in the toggleAlternate() method, however, that did not fix the error. I am new to Angular and am not sure what I can do to fix this.

Is there a way to not call the toggleAlternate() method on every render?

Currently, the UI is working fine, but I would like to remove the console errors.

Update

I am trying to make my work experience as a timeline in which every entry is alternate to the previous one.

the following is where toggleAlternate() is called:

<app-work-ex-position *ngFor="let job of year[Object.keys(year)[0]].jobs" [job]=job [alternate]="toggleAlternate()">
</app-work-ex-position>

this is how the <app-work-ex-position /> component looks like:

<app-work-ex-timeline-entry (expand)="onExpandEntry($event)" class="{{alternate ? 'alternate' : ''}}">

<app-work-ex-timeline-entry-dot class="{{isExpanded ? 'primary-circle' : 'primary-circle circle-not-expanded'}}"
                      [size]="30"
                      [isAlternate]="alternate">
</app-work-ex-timeline-entry-dot>
</app-work-ex-timeline-entry>

Based on what the value of alternate is returned from the parent component i set the css class.

David Walschots
  • 12,279
  • 5
  • 36
  • 59
  • `[alternate]` is interpreted on every render and therefore `toggleAlternate` is called every render. Could you show the component that contains the `alternate` property? – David Walschots Jan 05 '19 at 09:15
  • @ChaitanyaKhanna have try this `this.cd.detectChanges();` – Abhishek Jan 05 '19 at 10:04
  • @DavidWalschots I updated code above. let me know if something is still not clear. – Chaitanya Khanna Jan 05 '19 at 18:42
  • @Abhishek Can show me an example of how to use it. I did try this but maybe i m not using it properly. – Chaitanya Khanna Jan 05 '19 at 18:44
  • @ChaitanyaKhanna have you look at this (https://stackoverflow.com/questions/43375532/expressionchangedafterithasbeencheckederror-explained). or use this one in AppComponent `constructor(private cd: ChangeDetectorRef) { } ngAfterViewInit() { this.cd.detectChanges();}` – Abhishek Jan 06 '19 at 07:14
  • @Abhishek what you're proposing isn't a root-cause fix and won't work. It's important to understand how change detection works in Angular. That way, you'll not waste time on injecting the `ChangeDetectorRef` in many places. – David Walschots Jan 06 '19 at 09:22

1 Answers1

0

You should never call a function that changes component state from the HTML. This function will be called every change detection cycle and thus the component's state can never stabilise.

It seems that you want to set a CSS class within the component for every other instance. For this purpose you should use the even and odd variables exposed by *ngFor as can be found in the documentation.

Your code would need to be adapted as follows:

<app-work-ex-position 
    *ngFor="let job of year[Object.keys(year)[0]].jobs; even as isEven" 
    [isAlternate]="isEven">
</app-work-ex-position>
set isAlternate(value: boolean) {
  this.alternate = value;
}
David Walschots
  • 12,279
  • 5
  • 36
  • 59