zachThePerson
zachThePerson

Reputation: 704

Vue: Trigger event on automatic UI update

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

Answers (2)

blex
blex

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

Adem yal&#231;ın
Adem yal&#231;ın

Reputation: 206

you need async / await dispatch;

async addItem(){
   await dispatch()
   scroll to bottom of list
}

Upvotes: 0

Related Questions