Reputation: 704
I have a v-for list of items that are based on list stored in Vuex. I want it so that the list automatically scrolls to the bottom every time a new item is added. I figured the scrolling part out using this: Scroll to bottom of div?
The pseudocode is the following:
addItem(){
dispatch vuex event to add item
scroll to bottom of list
}
The issue I'm running into is that Vue seems to be updating the v-for list after the list is scrolled to the bottom, meaning that the list is always scrolled to the second to last item, instead of the last.
I fixed it by using a setTimout()
to wait 10ms, but it feels a little hacky. Is there a better way to trigger the scrollToBottom()
code on v-for list update?
Upvotes: 1
Views: 1134
Reputation: 25634
The normal way to wait for the next render is to use this.$nextTick(() => /* ... */)
. Here is a demo:
new Vue({
el: '#app',
'store': new Vuex.Store({
state: {
items: ["a", "b", "c", "d"],
index: 100
},
mutations: {
itemAdded(state) {
state.items.push(String.fromCharCode(++state.index));
}
},
actions: {
addItem({ commit }) {
commit('itemAdded');
}
}
}),
computed: {
...Vuex.mapState(['items'])
},
mounted() { this.scrollToBottom(); },
methods: {
addItem() {
this.$store.dispatch('addItem');
this.$nextTick(() => this.scrollToBottom()); // <-------------------------
},
scrollToBottom() {
this.$refs.list.scrollTop = this.$refs.list.scrollHeight;
}
}
});
ul { border: 1px solid black; height: 4em; overflow-y: scroll; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.5.1/vuex.min.js"></script>
<div id="app">
<div>
<button @click="addItem">Add item</button>
<ul ref="list">
<li v-for="(label, i) in items" :key="i">{{label}}</li>
</ul>
</div>
</div>
Upvotes: 1
Reputation: 206
you need async / await dispatch;
async addItem(){
await dispatch()
scroll to bottom of list
}
Upvotes: 0