Tive o mesmo problema, estou usando uma combinação AfterViewChecked
e @ViewChild
(Angular2 beta.3).
O componente:
import {..., AfterViewChecked, ElementRef, ViewChild, OnInit} from 'angular2/core'
@Component({
...
})
export class ChannelComponent implements OnInit, AfterViewChecked {
@ViewChild('scrollMe') private myScrollContainer: ElementRef;
ngOnInit() {
this.scrollToBottom();
}
ngAfterViewChecked() {
this.scrollToBottom();
}
scrollToBottom(): void {
try {
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
} catch(err) { }
}
}
O modelo:
<div #scrollMe style="overflow: scroll; height: xyz;">
<div class="..."
*ngFor="..."
...>
</div>
</div>
Claro que isso é muito básico. O AfterViewChecked
acionador sempre que a visualização é verificada:
Implemente esta interface para ser notificado após cada verificação da visualização do seu componente.
Se você tiver um campo de entrada para enviar mensagens, por exemplo, este evento é disparado após cada tecla (apenas para dar um exemplo). Mas se você salvar se o usuário rolou manualmente e, em seguida, pular o, scrollToBottom()
você ficará bem.
deixe-me corrigir isso
fonte
A solução mais simples e melhor para isso é:
Adicione esta
#scrollMe [scrollTop]="scrollMe.scrollHeight"
coisa simples no lado do modeloAqui está o link para DEMO DE TRABALHO (com aplicativo de bate-papo fictício) E CÓDIGO COMPLETO
fonte
Expression has changed after it was checked. Previous value: 'scrollTop: 1758'. Current value: 'scrollTop: 1734'
. Você resolveu isso?Eu adicionei uma verificação para ver se o usuário tentou rolar para cima.
Só vou deixar isso aqui se alguém quiser :)
e o código:
fonte
A resposta aceita dispara durante a rolagem pelas mensagens, o que evita isso.
Você quer um modelo como este.
Em seguida, você deseja usar uma anotação ViewChildren para assinar novos elementos de mensagem que estão sendo adicionados à página.
fonte
Considere usar
Consulte https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
fonte
Se quiser ter certeza de que vai rolar até o final depois que * ngFor for concluído, você pode usar isso.
Importante aqui, a variável "última" define se você está no último item, então você pode acionar o método "scrollToBottom"
fonte
fonte
Compartilhando minha solução, pois não fiquei completamente satisfeito com o resto. Meu problema
AfterViewChecked
é que às vezes estou rolar para cima e, por algum motivo, esse gancho de vida é chamado e rola para baixo, mesmo que não haja novas mensagens. Tentei usarOnChanges
mas isso foi um problema que me levou a esta solução. Infelizmente, usando apenasDoCheck
, ele estava rolando para baixo antes de as mensagens serem renderizadas, o que também não era útil, então eu os combinei para que DoCheck esteja basicamente indicandoAfterViewChecked
se deveria chamarscrollToBottom
.Fico feliz em receber feedback.
chat.component.html
chat.component.sass
fonte
const isScrolledDown = Math.abs(this.scrollable.nativeElement.scrollHeight - this.scrollable.nativeElement.scrollTop - this.scrollable.nativeElement.clientHeight) <= 3.0;
(onde 3.0 é a tolerância em pixels). Ele pode ser usado emngDoCheck
para condicionalmente não definidashouldScrollDown
paratrue
se o usuário é rolada manualmente.ngAfterViewChecked
com o outro booleano.shouldScrollDown
numberOfMessagesChanged
if (this.numberOfMessagesChanged && !isScrolledDown)
, mas acho que não entendeu a intenção da minha sugestão. Minha real intenção é não rolar para baixo automaticamente, mesmo quando uma nova mensagem é adicionada, se o usuário rolar manualmente para cima. Sem isso, se você rolar para cima para ver o histórico, o chat irá rolar para baixo assim que uma nova mensagem chegar. Isso pode ser um comportamento muito irritante. :) Então, minha sugestão foi verificar se o chat é rolado para cima antes de uma nova mensagem ser adicionada ao DOM e não rolagem automática, se for.ngAfterViewChecked
é tarde demais porque o DOM já mudou.A resposta de Vivek funcionou para mim, mas resultou em uma expressão que mudou depois de ser verificado um erro. Nenhum dos comentários funcionou para mim, mas o que fiz foi mudar a estratégia de detecção de alterações.
fonte
No angular using material design sidenav, tive que usar o seguinte:
fonte
fonte
Depois de ler outras soluções, a melhor solução que posso pensar, para que você execute apenas o que precisa é o seguinte: Você usa ngOnChanges para detectar a mudança adequada
E você usa ngAfterViewChecked para realmente impor a mudança antes de renderizar, mas depois que a altura total for calculada
Se você está se perguntando como implementar scrollToBottom
fonte