When dynamically assigning value to matTooltip
I get this error ExpressionChangedAfterItHasBeenCheckedError
.
I tried fixing it using detectChanges()
but then I get this error Maximum call stack size exceeded
.
Requirement: I need to show tooltip when text is truncated.
Html
<div class="container">
<p *ngFor="let each of tooltipsData" #element [matTooltip]="isTextTruncated(element) ? each : null">{{each}}</p>
</div>
Typescript
tooltipsData = [
"Lorem Ipsum",
"Lorem Ipsum is simply dummy text",
"Lorem",
"Lorem Ipsum is simply dummy text of the printing and typesetting"
];
isTextTruncated(element: any) {
// this.cdr.detectChanges();
return element.scrollWidth > element.clientWidth;
}
TL;DR - call
detectChanges()
inngAfterViewInit()
Example
import { Component, AfterViewInit, ChangeDetectorRef } from '@angular/core';
...
constructor(private cdr: ChangeDetectorRef) { }
...
ngAfterViewInit() {
this.cdr.detectChanges();
}
Explanation
Angular runs list of lifecycle hooks starting from ngOnInit
to ngAfterViewInit
. In this process angular stores previous values and compare with current value (e.g., In ngOnInit
when x
is false
and in ngAfterViewInit
x
is true
), when value is changed while lifecycle hooks
are running then this error occurs Expression...Previous value: 'message: false'. Current value: 'message: true'.
My scenario
I am displaying tooltip based on DOM manipulation (when text is truncated), So in ngOnInit
no elements are loaded in DOM, So initially value is null
and in ngAfterViewInit
elements are loaded and tooltip value changed from null
to Lorem Ipsum is simply dummy text
. So we need to tell angular to detect changes in ngAfterViewInit
.
Other Scenario Async API
Update
The above solution works in example stackblitz, but in my real angular project it doesn't work because I get tooltip value from Async API.
So I called
detectChanges()
after API is completed.