In vuejs, I'm developing a conversation chat between two users. I have nested component like this
Chat
->ChatLog
-> ChatMessage
->ChatComposer
The chat component has the structure of the chat (a panel in bootstrap) and also that's where I retrieve with Axios, when the page is loaded, all the messages from the database.
axios
.get('/conversation/'+this.conversation.id+'/message')
.then((response) => {
this.messages = response.data;
this.manageHeightChat();
this.scrollToEnd();
});
And when the I get all the message, I dispatch them to the ChatLog
component
<chat-message v-for="message in messages" v-bind:message="message" v-bind:user="user"></chat-message>
which dispatch each message to the ChatMessage
component.
So when the callback method is called with all the messages, they are dispatched to the other components and then the two methods manageHeightChat
and scrollToEnd
are called.
scrollToEnd() {
var container = this.$refs.chatlog;
container.scrollTop = container.scrollHeight;
console.log(container.scrollHeight);
}
The problem is that the last method (scrollToEnd
) is called before the messages are rendered by the ChatLog
and ChatMessage
so the container.scrollHeight
is not the good size.
To verify it I added something like :
setTimeout(function () {
this.scrollToEnd();
}.bind(this), 1000);
And everything was working fine.
So how and where would you put some event to tell chat that the content is rendered and that I can call the scrollToEnd
method ?
See nextTick. When you set the message data, you need to wait for Vue to update the DOM. That is what nextTick
is for. Use it pretty much like you're using setTimeout
axios
.get('/conversation/'+this.conversation.id+'/message')
.then((response) => {
this.messages = response.data;
this.manageHeightChat();
this.$nextTick(this.scrollToEnd.bind(this));
});