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;
}
}