How to update Vue component's property with fetched data - vue.js

Vue.component('test', {
template: `some html`,
data() {
{
return {
somedata: 'hey, starting!'
}
}
},
methods: {
fetchdata: function fetchdata() {
fetch('http://localhost:5000/getmesome')
.then(response => response.json()).then(data => this.somedata = data
);
}
}, created() {
this.fetchdata();
console.log(this.somedata); //returns 'hey starting' not the fetched data.
}
});
As shown in the code comment, this is not refreshing the property with the fetched data. How can I do it?
Thanks.

fetchdata() will return immediately while the request is still in progress since it is an async operation. console.log(this.somedata) will be executed before the fetch operation has completed.
This is a basic async misunderstanding; I would suggest you read up on asynchronous JavaScript topics (promises, async and await, etc).
Either of these solutions will work:
methods: {
fetchdata() {
return fetch('http://localhost:5000/getmesome')
.then(response => response.json())
.then(data => this.somedata = data);
}
},
created() {
this.fetchdata()
.then(() => console.log(this.somedata));
}
methods: {
async fetchdata() {
const res = await fetch('http://localhost:5000/getmesome');
const data = await res.json();
this.somedata = data;
}
},
async created() {
await this.fetchdata();
console.log(this.somedata);
}

Related

Setting variables in Vue 2 using Fetch API: Async Task

am relatively new to async tasks but I cant comprehend why my fetch API wont set my vue variable but on console.log it shows the Variable. I’ve tried Async/Await in vain. See the code segment below on my .vue component.
data(){
return{
pg:’’
}
},
methods:{
insertData(){
this.insertDataAPI()
console.log(this.pg) //THIS GIVES EMPTY STRING INSTEAD OF FETCHED DATA
},
insertDataAPI(){
fetch(‘EndPoint’, {
method:'POST',
headers:{
// some headers
},
body:JSON.stringify({
// some data
})
}).then( res => res.json())
.then(async page =>this.pg = await page //Console.log logs the page fine
// but variable pg is not set
).catch( (err) => {
console.log(err)
});
}
}
async/await is a different handler for promise.then().catch(). As fetch returns a promise you can use both
Option 1, await the fetch:
methods: {
insertData() {
this.insertDataAPI();
console.log(this.pg);
},
insertDataAPI() {
const response = await fetch(‘EndPoint’, {
method:'POST',
headers:{
// some headers
},
body:JSON.stringify({
// some data
})
});
this.pg = response.json();
}
}
Option 2, await the insertDataAPI:
methods: {
async insertData() {
await this.insertDataAPI();
console.log(this.pg);
},
insertDataAPI() {
return fetch(‘EndPoint’, {
method:'POST',
headers:{
// some headers
},
body:JSON.stringify({
// some data
})
}).then(res => res.json())
.then(page => this.pg = page)
.catch( (err) => {
console.log(err)
});
}
}
let's try to read about the way async/ await work
you can try on Axiost lib for easier to fetch APIs

Vue: executing two methods in specific order

I have a Vue application. I would like to retrieve entries (from a database) based on a userid. I have the following methods in Vue:
export default {
name: 'Entries',
data() {
return {
userid: null
};
},
methods: {
getEntries() {
this.getUserID();
console.log("userid getEntries: " + this.userid);
axios.get('/entries', this.userid)
.then((res) => {
this.entries = res.data;
console.log(this.entries);
})
.catch((error) => {
console.error(error);
});
},
getUserID() {
axios.get('/userid')
.then((res) => {
this.userid = res.data;
console.log("userid getUserId: " + this.userid );
})
.catch((error) => {
console.error(error);
});
},
},
created() {
this.getEntries();
}
};
Within the getEntries method, I'm immediately calling the getUserID function. I would assume this sets the variable userid to the value retrieved from the getUserID method.
Instead I get the following output in the browser console, in exactly this order:
userid getEntries: null
userid getUserId: user_a
Why does it print first the console output from the getEntries function? And why is this null if it first executes the getUserID method?
How could I change is so that the axios call /entries can pass the userid.
axios calls are async, if you need the userid populated before anything else is called, then you should populate before anything else is called, in mounted/created.
Then you can react to its change with a watcher. You could call getEntries when the getUserID call resolves but it's dirty and couples the two methods.
And don't forget to assign entries in data.
This will work:
export default {
name: 'Entries',
data() {
return {
userid: null,
entries: []
};
},
watch: {
userid (v) {
if (v) this.getEntries()
}
},
mounted() {
this.$nextTick(this.getUserID)
},
methods: {
getEntries() {
console.log("userid getEntries: " + this.userid);
axios.get('/entries', this.userid)
.then((res) => {
this.entries = res.data;
console.log(this.entries);
})
.catch((error) => {
console.error(error);
});
},
getUserID() {
axios.get('/userid')
.then((res) => {
this.userid = res.data;
console.log("userid getUserId: " + this.userid);
})
.catch((error) => {
console.error(error);
});
}
}
};
Using async/await
export default {
name: 'Entries',
data() {
return {
userid: null,
entries: []
};
},
watch: {
userid (v) {
if (v) this.getEntries()
}
},
mounted() {
this.$nextTick(this.getUserID)
},
methods: {
async getEntries() {
try {
const { data } = await axios.get('/entries', this.userid)
this.entries = data;
} catch (error) {
console.error(error);
}
},
async getUserID() {
try {
const { data } = await axios.get('/userid')
this.userid = data;
} catch (error) {
console.error(error);
}
}
}
};
Since getUserId is asynchronous, it doesn't return immediately. You therefore need to wait for it to return before continuing. This can be done using then but, nested Promises are a bit unpleasant to work with. A simpler option is to use async/await instead:
async getEntries() {
await this.getUserID();
console.log("userid getEntries: " + this.userid);
axios.get('/entries', this.userid)
.then((res) => {
this.entries = res.data;
console.log(this.entries);
})
.catch((error) => {
console.error(error);
});
},

How can I update the comments without refreshing it?

First, I'm using vuex and axios.
store: commentService.js
components:
CommentBox.vue (Top components)
CommentEnter.vue (Sub components)
This is the logic of the code I wrote.
In the store called commentService.js, there are mutations called commentUpdate.
And There are actions called postComment and getComment.
At this time, In the component called CommentBox dispatches getComment with async created().
Then, in getComment, commentUpdate is commited and executed.
CommentUpdate creates an array of comments inquired by getComment and stores them in a state called commentList.
Then I'll get a commentList with "computed".
CommentEnter, a sub-component, uses the commentList registered as compounded in the CommentBox as a prop.
The code below is commentService.js.
import axios from 'axios'
export default {
namespaced: true,
state: () => ({
comment:'',
commentList: []
}),
mutations: {
commentUpdate(state, payload) {
Object.keys(payload).forEach(key => {
state[key] = payload[key]
})
}
},
actions: {
postComment(state, payload) {
const {id} = payload
axios.post(`http://??.???.???.???:????/api/books/${id}/comments`, {
comment: this.state.comment,
starRate: this.state.starRate
}, {
headers: {
Authorization: `Bearer ` + localStorage.getItem('user-token')
}
})
.then((res) => {
console.log(res)
this.state.comment = ''
this.state.starRate = ''
)
.catch((err) => {
alert('댓글은 한 책당 한 번만 작성할 수 있습니다.')
console.log(err)
this.state.comment = ''
this.state.starRate = ''
})
},
async getComment({commit}, payload) {
const {id} = payload
axios.get(`http://??.???.???.???:????/api/books/${id}/comments`)
.then((res) => {
console.log(res)
const { comment } = res.data.commentMap
commit('commentUpdate', {
commentList: comment
})
})
.catch((err) => {
console.log(err)
commit('commentUpdate', {
commentList: {}
})
})
}
}
}
The code below is CommentBox.vue
computed: {
commentList() {
return this.$store.state.commentService.commentList
}
},
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
}
},
async created() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
The code below is CommentEnter.vue
created() {
this.userComment = this.comment
},
props: {
comment: {
type: Object,
default: () => {}
}
},
I asked for a lot of advice.
There were many comments asking for an axios get request after the axios post request was successful.
In fact, I requested an axios get within .then() of the axios post, and the network tab confirmed that the get request occurred normally after the post request.
But it's still not seen immediately when I register a new comment.
I can only see new comments when I refresh it.
How can I make a new comment appear on the screen right away when I register it?
Can't you just call getComment when postComment is finished?
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
}).then(function() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
})
}
},
}
Or since you're using async:
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
await this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
},
}

Vuex update state by using store actions

I have two functions in my store, one that gets data by calling API and one that toggles change on cell "approved". Everything working fine, except that when I toggle this change it happens in database and I get the response that it is done but It doesn't update on UI.
I am confused, what should I do after toggling change to reflect change on UI, should I call my API from .then or should I call action method responsible for getting data from server.
export default {
state: {
drivers: {
allDrivers:[],
driversError:null
},
isLoading: false,
token: localStorage.getItem('token'),
driverApproved: null,
driverNotApproved: null
},
getters: {
driversAreLoading (state) {
return state.isLoading;
},
driverError (state) {
return state.drivers.driversError;
},
getAllDrivers(state){
return state.drivers.allDrivers
}
},
mutations: {
getAllDrivers (state) {
state.isLoading=true;
state.drivers.driversError=null;
},
allDriversAvailable(state,payload){
state.isLoading=false;
state.drivers.allDrivers=payload;
},
allDriversNotAvailable(state,payload){
state.isLoading=false;
state.drivers.driversError=payload;
},
toggleDriverApproval(state){
state.isLoading = true;
},
driverApprovalCompleted(state){
state.isLoading = false;
state.driverApproved = true;
},
driverApprovalError(state){
state.isLoading = false;
state.driverError = true;
}
},
actions: {
allDrivers (context) {
context.commit("getAllDrivers")
return new Promise((res,rej)=>{
http.get('/api/admin/getAllDrivers').then(
response=>{
if (response.data.success){
let data=response.data.data;
data=data.map(function (driver) {
return {
/* response */
};
});
context.commit("allDriversAvailable",data);
res();
}else {
context.commit("allDriversNotAvailable",response.data)
rej()
}
})
.catch(error=>{
context.commit("allDriversNotAvailable",error.data)
rej()
});
});
},
toggleDriverApproval (context, payload){
return new Promise((res, rej)=>{
http.post("/api/admin/toggleDriverApproval",{
driver_id: payload
})
.then( response => {
context.commit('driverApprovalCompleted');
res();
}).catch( error =>{
context.commit('driverApprovalError');
rej()
})
})
}
}
}
and here is the code on the view, I wrote the necessary code for better clarification of the problem
export default {
name: 'Drivers',
data: () => ({
data: [],
allDrivers: [],
driversErrors: []
}),
created() {
this.$store
.dispatch('allDrivers')
.then(() => {
this.data = this.$store.getters.getAllDrivers
})
.catch(() => {
this.errors = this.$store.getters.driverError
})
},
computed: {
isLoading() {
return this.$store.getters.driversAreLoading
}
},
methods: {
verify: function(row) {
console.log(row)
this.$store.dispatch('toggleDriverApproval', row.id).then(() => {
this.data = this.$store.getters.getAllDrivers
console.log('done dis')
})
},
},
}
if I understand your issue, you want the UI displaying your data to change to the updated data after making a post request.
If you are using Vuex you will want to commit a mutation, and use a getter display the data.
I am not sure how your post request is being handled on the server but if successful typically you would send a response back to your front end with the updated data, and commit a mutation with the updated data.
Example:
Make a Post request
toggleDriverApproval (context, payload){
return new Promise((res, rej)=>{
http.post("/api/admin/toggleDriverApproval",{
driver_id: payload
})
.then( response => {
context.commit('driverApprovalCompleted', response.data);
res();
}).catch( error =>{
context.commit('driverApprovalError', error.response.data);
rej()
})
})
}
If succesful commit the mutation
.then( response => {
context.commit('driverApprovalCompleted', response.data);
res();
})
response.data being your data you want to mutate the state with.
Mutation Example:
customMutation(state, data) {
state.driverApproval = data
}
Getter Example:
driver(state) {
return state.driverApproval
}
displaying the getter in a template
<template>
<div v-if="driver">{{driver}}</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
name: Example,
computed: {
driver() {
return this.$store.getters.driver
},
// or use mapGetters
...mapGetters(['driver'])
}
}
</script>
more examples can be found at Vuex Docs

Cannot assign axios response value to a variable - vue.js

I created an array lists that contains a few strings.
Now I want to loop through lists (i.e., in getSubs()) and make an Axios request. This request should contain one string from lists each time.
My code:
computed: {
subscribers: {
get() {
return this.$store.state.subscribers;
},
set(value) {
this.$store.commit('updateSubscribers', value);
},
},
},
methods: {
getLodzkie() {
axios
.get(`correct_domain/lodzkietargi/get`)
.then((response) => {
this.subscribers = [];
this.subscribers.push.apply(this.subscribers, response.data)
})
.catch(function(error) {
console.log(error);
})
},
getSubs() {
function getSub(value) {
axios
.get(`correct_domain/${value}/get`)
.then((response) => {
this.subscribers.push.apply(this.subscribers, response.data)
})
.catch(function(error) {
console.log(error);
});
console.log(value);
}
this.lists.forEach(function(entry) {
getSub.call(null, entry);
});
},
getLodzkie() works beautifully
Thank You a lot #ourmandave. That helped me perfectly.
Rewrote function below:
getSubs() {
let listsReqs = this.lists.map(list => {
return axios.get(`correct_domain/${list}/get`);
});
axios.all(listsReqs)
.then(axios.spread((...responses) => {
responses.forEach(res => this.subscribers.push.apply(this.subscribers, res.data));
})
)},