I am trying to automatically scroll to the bottom of a div that contains a list of elements once a new element has been added.
Since adding and removing elements is done via Axios using an API, I have to wait for a response from the server in order to update my state in Vuex.
This means that, once an element is added in my state, every time I call the "scrollDown" function, the function scrolls to the second last element (due to the asynchronous Axios call not being registered yet).
My question is, how do I wait for the action in Vuex to finish and then call the function in my ponent to scroll to the bottom of my div?
I tried using watchers, puted properties, sending props, tracking changes from the actual state in Vuex and none of that worked...
// VUEX
const state = {
visitors: [],
url: 'API URL',
errors: []
}
const mutations = {
ADD_VISITOR(state, response) {
const data = response.data;
data.Photos = [];
state.visitors.data.push(data);
},
}
const actions = {
addVisitor: ({ mit }, insertion) => {
axios
.post(state.url + 'api/visitor', {
name: insertion.visitorName
})
.then(response => {
mit('ADD_VISITOR', response);
})
.catch(error => state.errors.push(error.response.data.message));
state.errors = [];
},
}
// MY COMPONENT FROM WHERE THE ACTIONS ARE BEING DISPATCHED
<div ref="scroll" class="visitors-scroll">
<ul v-if="visitors.data && visitors.data.length > 0" class="list-group visitors-panel">
<!-- Displaying appVisitor ponent and sending data as a prop -->
<app-visitor v-for="visitor in visitors.data" :key="visitor.id" :visitor="visitor"></app-visitor>
</ul>
</div>
methods: {
// Function that dispatches the "addVisitor" action to add a new visitor to the database
newVisitor() {
const insertion = {
visitorName: this.name
};
if (insertion.visitorName.trim() == "") {
this.errors.push("Enter a valid name!");
} else {
this.$store.dispatch("addVisitor", insertion);
this.name = "";
}
this.errors = [];
this.scrollDown(); // I WANT TO CALL THIS FUNCTION WHEN AXIOS CALL IS FINISHED AND MUTATION IN VUEX IS COMPLETED
},
scrollDown() {
this.$refs.scroll.scrollTop = this.$refs.scroll.scrollHeight;
}
},
Any help is appreciated!
I am trying to automatically scroll to the bottom of a div that contains a list of elements once a new element has been added.
Since adding and removing elements is done via Axios using an API, I have to wait for a response from the server in order to update my state in Vuex.
This means that, once an element is added in my state, every time I call the "scrollDown" function, the function scrolls to the second last element (due to the asynchronous Axios call not being registered yet).
My question is, how do I wait for the action in Vuex to finish and then call the function in my ponent to scroll to the bottom of my div?
I tried using watchers, puted properties, sending props, tracking changes from the actual state in Vuex and none of that worked...
// VUEX
const state = {
visitors: [],
url: 'API URL',
errors: []
}
const mutations = {
ADD_VISITOR(state, response) {
const data = response.data;
data.Photos = [];
state.visitors.data.push(data);
},
}
const actions = {
addVisitor: ({ mit }, insertion) => {
axios
.post(state.url + 'api/visitor', {
name: insertion.visitorName
})
.then(response => {
mit('ADD_VISITOR', response);
})
.catch(error => state.errors.push(error.response.data.message));
state.errors = [];
},
}
// MY COMPONENT FROM WHERE THE ACTIONS ARE BEING DISPATCHED
<div ref="scroll" class="visitors-scroll">
<ul v-if="visitors.data && visitors.data.length > 0" class="list-group visitors-panel">
<!-- Displaying appVisitor ponent and sending data as a prop -->
<app-visitor v-for="visitor in visitors.data" :key="visitor.id" :visitor="visitor"></app-visitor>
</ul>
</div>
methods: {
// Function that dispatches the "addVisitor" action to add a new visitor to the database
newVisitor() {
const insertion = {
visitorName: this.name
};
if (insertion.visitorName.trim() == "") {
this.errors.push("Enter a valid name!");
} else {
this.$store.dispatch("addVisitor", insertion);
this.name = "";
}
this.errors = [];
this.scrollDown(); // I WANT TO CALL THIS FUNCTION WHEN AXIOS CALL IS FINISHED AND MUTATION IN VUEX IS COMPLETED
},
scrollDown() {
this.$refs.scroll.scrollTop = this.$refs.scroll.scrollHeight;
}
},
Any help is appreciated!
Share Improve this question asked Mar 29, 2019 at 14:05 user7654617user76546172 Answers
Reset to default 4In vuex dispatched action returns a Promise. In case of your code its empty Promise, because there is nothing to return. You need to return/pass your axios Promise and then wait for it in your ponent. Look at this fixed code:
// VUEX
const state = {
visitors: [],
url: 'API URL',
errors: []
}
const mutations = {
ADD_VISITOR(state, response) {
const data = response.data;
data.Photos = [];
state.visitors.data.push(data);
},
}
const actions = {
addVisitor: ({ mit }, insertion) => {
return axios
.post(state.url + 'api/visitor', {
name: insertion.visitorName
})
.then(response => {
mit('ADD_VISITOR', response);
})
.catch(error => state.errors.push(error.response.data.message));
state.errors = [];
},
}
// MY COMPONENT FROM WHERE THE ACTIONS ARE BEING DISPATCHED
<div ref="scroll" class="visitors-scroll">
<ul v-if="visitors.data && visitors.data.length > 0" class="list-group visitors-panel">
<!-- Displaying appVisitor ponent and sending data as a prop -->
<app-visitor v-for="visitor in visitors.data" :key="visitor.id" :visitor="visitor"></app-visitor>
</ul>
</div>
methods: {
// Function that dispatches the "addVisitor" action to add a new visitor to the database
newVisitor() {
const insertion = {
visitorName: this.name
};
if (insertion.visitorName.trim() == "") {
this.errors.push("Enter a valid name!");
} else {
this.$store.dispatch("addVisitor", insertion)
.then(() => {
this.scrollDown();
})
this.name = "";
}
this.errors = [];
},
scrollDown() {
this.$refs.scroll.scrollTop = this.$refs.scroll.scrollHeight;
}
},
You could try using the async/await
syntax.
This means when it will wait until this.$store.dispatch("addVisitor", insertion)
is resolved, that means until response from the API is there, the next lines of code will not be executed.
methods: {
// Function that dispatches the "addVisitor" action to add a new visitor to the database
async newVisitor() {
const insertion = {
visitorName: this.name
};
if (insertion.visitorName.trim() == "") {
this.errors.push("Enter a valid name!");
} else {
await this.$store.dispatch("addVisitor", insertion);
this.name = "";
}
this.errors = [];
this.scrollDown();
},
scrollDown() {
this.$refs.scroll.scrollTop = this.$refs.scroll.scrollHeight;
}
}
Edit: And in your Vueux action, make sure to add a return
statement.
const actions = {
addVisitor: ({ mit }, insertion) => {
return axios
.post(state.url + 'api/visitor', {
name: insertion.visitorName
})
.then(response => {
mit('ADD_VISITOR', response);
})
.catch(error => state.errors.push(error.response.data.message));
state.errors = [];
},
}