I am new to Angular2 and Angular in general and am trying to get some jQuery to fire after the dom is updated when the data of a component is changed. The jQuery needs to calculate heights of elements so I can't exactly just use the data. Unfortunately it looks like onAllChangesDone only fires after data changes, not the dom.
Asked
Active
Viewed 8.3k times
48
-
Related to this ["Angular 2 with Jquery"](http://stackoverflow.com/questions/30623825/how-to-use-jquery-with-angular2) issue? Try `setTimeout`. – shmck Jul 01 '15 at 23:16
-
@shmck, that seems to only work on construction, I need something that will allow the function to run each time the data is changed and the dom is updated. – ComputerWolf Jul 02 '15 at 01:12
-
1new callbacks have been added in alpha37 https://github.com/angular/angular/blob/2.0.0-alpha.37/CHANGELOG.md core: added afterContentInit, afterViewInit, and afterViewChecked hooks (d49bc43), closes #3897 – Mourad Zouabi Sep 10 '15 at 11:55
1 Answers
67
The only solution I've found with the lifecycle hook ngAfterViewChecked.
Example of a chat where you have to scroll down the messages list after adding and rendering a new message:
import {Component, AfterViewChecked, ElementRef} from 'angular2/core';
@Component({
selector: 'chat',
template: `
<div style="max-height:200px; overflow-y:auto;" class="chat-list">
<ul>
<li *ngFor="#message of messages;">
{{ message }}
</li>
</ul>
</div>
<textarea #txt></textarea>
<button (click)="messages.push(txt.value); txt.value = '';">Send</button>
`
})
export class ChatComponent implements AfterViewChecked {
public messages: any[] = [];
private _prevChatHeight: number = 0;
constructor (public element: ElementRef) {
this.messages = ['message 3', 'message 2', 'message 1'];
this.elChatList = this.element.nativeElement.querySelector('.chat-list');
}
public ngAfterViewChecked(): void {
/* need _canScrollDown because it triggers even if you enter text in the textarea */
if ( this._canScrollDown() ) {
this.scrollDown();
}
}
private _canScrollDown(): boolean {
/* compares prev and current scrollHeight */
var can = (this._prevChatHeight !== this.elChatList.scrollHeight);
this._prevChatHeight = this.elChatList.scrollHeight;
return can;
}
public scrollDown(): void {
this.elChatList.scrollTop = this.elChatList.scrollHeight;
}
}

Artod
- 891
- 7
- 12
-
7Don't use AfterViewChecked, use AfterViewInit (called only once, after the first AfterViewChecked) instead. https://angular.io/guide/lifecycle-hooks – Nico Toub Jul 17 '17 at 09:20
-
24@NicoToub AfterViewInit sometimes gets called before the DOM is constructed. I found using AfterViewChecked with manually handled flag that will allow code running only once the only option. It's not elegant but it works. – George Knap Aug 16 '17 at 12:03
-
1@GeorgeKnap, sorry, may i ask you to share the code which uses AfterViewChecked with the manually handled flag? Thanks in advance! – lucifer63 Jul 06 '18 at 16:40
-
4@lucifer63 You can have a conditional variable, like `initialViewCheck = false`, and in `ngAfterViewChecked` function, you need to write an `if` condition evaluating the boolean value of `initialViewCheck`. If it is `false` (`if (!this.initialViewCheck)`), set the variable to `true` inside the condition and also write the code inside the condition that you want to be executed only once. So, whenever `ngAfterViewChecked` is called then, the condition fails because `initialViewCheck` is set `true`. – Wolverine Jul 07 '18 at 18:16
-
1Dont use AfterViewChecked . It caused performance issues to us since it loads gets fired multiple times ! – Shravan Hebbar Aug 30 '19 at 14:05
-
@ShraavanHebbar it causes serious performance issues. Do you have any alternative? – siddharth shah Mar 18 '20 at 08:45