Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue scroll div to top inside method

Learning Vue. Trying to get a chat window div to scroll to the top when a new chat entry is found.

My Vue component is:

const app = new Vue({ 
    el: '#toolbar-chat',

    data: {
        messages: []
    },

    created() {
        this.fetchMessages();

        Echo.private(chat_channel)
            .listen('ChatMessageSent', (e) => {
                this.messages.unshift({
                    message: e.data.message,
                    player: e.data.player.nickname
                });
            });
    },

    methods: {
        fetchMessages() {
            axios.get(chat_get_route)
                .then(response => {
                    this.messages = response.data;
                });
        },

        addMessage(message) {
            this.messages.unshift(message);

            this.$nextTick(() => {
                this.$refs.msgContainer.scrollTop = 0;
            });

            axios.post(chat_send_route, message)
                .then(response => {
                    console.log(response.data);
                });

        }
    }
});

My chat message Template

<template>
    <div ref="msgContainer" class="toolbar-chat">
        <div class="row">
            <div class="col-xs-12" v-for="message in messages">
                <strong class="primary-font">
                    {{ message.player.nickname }}:
                </strong>
                {{ message.message }}
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['messages']
    };
</script>

My chat send template

<template>
    <div class="input-group input-group-sm">
        <input id="btn-input" type="text" class="form-control" value="" required="required"  maxlength="140" placeholder="Type your message here..." v-model="newMessage" @keyup.enter="sendMessage">
        <div class="input-group-btn">
            <button class="btn btn-primary" type="button"  id="btn-chat" @click="sendMessage">
                <i class="fa fa-paper-plane"></i>
            </button>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['player'],

        data() {
            return {
                newMessage: ''
            }
        },

        methods: {
            sendMessage() {
                this.$emit('chatmessagesent', {
                    player: this.player,
                    message: this.newMessage
                });

                this.newMessage = ''
            }
        }
    }
</script>

And in my page I include the templates

<div class="col-xs-12 col-md-4" id="toolbar-chat">
    <chat-messages :messages="messages"></chat-messages>
    <chat-form v-on:chatmessagesent="addMessage" :player="{{ Auth::user() }}"></chat-form>
</div>

A message adds to the list OK, but I get this error:

[Vue warn]: Error in nextTick: "TypeError: Cannot set property 'scrollTop' of undefined"

Is it the way the element is named (camelCase)? What have I missed.

like image 202
TheRealPapa Avatar asked Feb 06 '26 17:02

TheRealPapa


1 Answers

Since the element you want to scroll is within a component, you should implement a method on that component that you can call.

For example, in your chat-messages component...

methods: {
  scrollToTop () {
    this.$el.scrollTop = 0
  }
}

and in your Vue instance, add a ref for that component...

<chat-messages ref="messages"...

and in the addMessage method...

this.$refs.messages.scrollToTop()
like image 178
Phil Avatar answered Feb 08 '26 06:02

Phil