zcbd
zcbd

Reputation: 85

Expression has changed after it was checked, why and how to fix it?

I'm getting this exception when I'm trying to do this - messages.component.html:

<div *ngFor = "let message of messages | async">
      <div *ngIf = "needToPrint(message.timestamp | date: 'dd/MM/yy')">
        <p class = "date-stamp"> {{ message.timestamp | date: "MM/dd/yy" }} </p> 
      </div> 
.
.
</div>

needToPrint function - messages.component.ts:

 import { AfterViewChecked, ElementRef, ViewChild, Component, OnInit } from '@angular/core';
import { FirebaseListObservable } from 'angularfire2';
import { AF } from "../../providers/af";
import { ChangeDetectorRef } from "@angular/core";


@Component({
  //selector: 'app-messages',
  templateUrl: './messages.component.html',
  styleUrls: ['./messages.component.css']
})

export class MessagesComponent implements OnInit, AfterViewChecked
{
  @ViewChild('scrollMe') private myScrollContainer: ElementRef;

  savedDate: string = '';

/* some code... */

  // ==================================================

  constructor(public afService: AF, private cdRef:ChangeDetectorRef) 
  {
      this.messages = this.afService.messages;
  }
  // ==================================================
  // If need to print the date ahead

  needToPrint(date)
  {
    if (this.savedDate != date)
    {
      this.savedDate = date;
      return true;
    }

    return false;
  }



  sendMessage()
  {
    this.afService.sendMessage(this.newMessage);
    this.newMessage = '';
  }

  // ==================================================

 ngAfterViewChecked() 
 {
    // this.scrollToBottom();
  }

  scrollToBottom(): void 
  {
    try {
        this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
    } catch(err) { }
  }


}

I understand that this exception is appear only in dev mode but how can I fix it? (I tried to read about this but still, no succeed to fix it).

thanks.

Upvotes: 1

Views: 1543

Answers (1)

AVJT82
AVJT82

Reputation: 73337

Not tested, but hopefully this helps.

So as mentioned, the error is caused by calling a function in template, i.e

needToPrint(message.timestamp | date: 'dd/MM/yy')

I strongly suggest that you would refactor your code as such that you are not calling a function from the template, it is considered bad practice for change detection reasons, and in worse case it can cause an infinite loop: *ngFor running an infinite loop in angular2

The workaround for this though, could be invoking change detection manually, by using ChangeDetectorRef. Import it, inject in constructor and use it inside needToPrint-function:

import { ChangeDetectorRef } from '@angular/core';

constructor(private ref: ChangeDetectorRef) { }

needToPrint(date) {
  if (this.savedDate != date){
    this.savedDate = date;
    this.ref.detectChanges();
    return true;
  }
  this.ref.detectChanges();
  return false;
}

Upvotes: 1

Related Questions