aixos reponse data can not assign to Vue instance's data - vue.js

In my vue.js project, i get an array data by axios, and want to assign to bookList variable, but failed, bookList still equal to [], could you tell me why?
export default {
...
data () {
return {
bookList: []
}
},
mounted: function() {
this.$nextTick(function(){
this.viewBooks();
});
},
methods: {
viewBooks: function() {
axios.get('/books.json')
.then(res=>{
this.bookList = res.data.bookList;
})
.catch(error=>{
console.log(error);
});
}
}

The callback is on a different scope...this should work
methods: {
viewBooks: function() {
let self = this;
axios.get('/books.json')
.then(res=>{
self.bookList = res.data.bookList;
})
.catch(error=>{
console.log(error);
});
}
There's also a different answer here

Related

vue updating data on create()

I am trying to update an array from my view data() inside my created hook() but my console says that the allFish is undefined. I'm not so great with vue data scoping yet and I was hoping someone could let me know if this is a diction issue, or if there's a better way to update my data on create() when receiving data from a get request and then adding it to an array inside my data.
my current app.vue
export default {
name: "App",
components: {
WebMap
},
data: () => ({
coords: {
latitude: -118,
longitude: 34,
},
date: '',
fishType: '',
allFish: []
}),
created(){
this.allFish = this.fetchFishLocations()
},
methods: {
fetchFishLocations(){
axios.get('http://localhost:3000/allFish')
.then(function (response) {
// handle success
console.log(response.data.fish);
return response.data.fish
})
.catch(function (error) {
// handle error
console.log(error);
})
},
async updateCenter() {
console.log(this.allFish) //check to see if allFish is defined
await this.getLocation();
this.addFishToDb()
},
},
};
The function which is called fetchFishLocations just returns undefined.
You'd better learn about the use of promise.
By the way, it's easier to use the arrow function
// solution 1
created(){
this.fetchFishLocations()
},
methods: {
fetchFishLocations(){
const that = this
axios.get('http://localhost:3000/allFish')
.then(function (response) {
// handle success
console.log(response.data.fish);
that.allFish = response.data.fish
})
.catch(function (error) {
// handle error
console.log(error);
})
}
}
// solution 2
created(){
const that = this
this.fetchFishLocations()
.then(function (response) {
// handle success
console.log(response.data.fish);
that.allFish = response.data.fish
})
.catch(function (error) {
// handle error
console.log(error);
})
},
methods: {
fetchFishLocations(){
return axios.get('http://localhost:3000/allFish')
}
}
You need fill allFish in axios->then method.
...
created() {
this.fetchFishLocations();
},
methods: {
fetchFishLocations(){
axios.get('http://localhost:3000/allFish')
.then(function (response) {
// handle success
console.log(response.data.fish);
this.allFish = response.data.fish;
})
.catch(function (error) {
// handle error
console.log(error);
})
},
}
...

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

How to set a value inside a variable on data() using a function?

I'm creating a Vue.js component inside a Laravel App.
After I catch the response with an axios request, I can't put a value inside a variable on method data()
Here is the code:
app.js
require('./bootstrap')
window.Vue = require('vue')
Vue.component('card', require('./components/card.vue'))
let app = new Vue({
el: '#app'
})
card.vue
<script>
module.exports = {
props: [
'name'
],
data: function() {
return {
projects: [],
}
},
mounted() {
this.getProjects() // NOT WORK?
},
methods: {
getProjects: function() {
axios.get('/api/v1/getProjects').then(function (response) {
console.log(response.data)
this.projects = response.data // NOT WORK
}).catch(function (error) {
console.log(error)
}).then(function () {
})
},
}
}
</script>
It's because of using this in response callback. You should use an arrow function (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) or save the context in separate variable.
Try to add .bind(this) or replace function with =>:
getProjects: function() {
axios.get('/api/v1/getProjects').then((response) => {
console.log(response.data)
this.projects = response.data // NOT WORK
}).catch((error) => {
console.log(error)
}).then(function () {
})
},

Vue - Data not computed in time before mount

I'm learning Vue and I've run into a problem where my data returns undefined from a computed method. It seems that the data is not computed by the time the component is mounted, probably due to the get request - wrapping my this.render() in a setTimeout returns the data correctly. Setting a timeout is clearly not sensible so how should I be doing this for best practice?
Home.vue
export default {
created() {
this.$store.dispatch('retrievePost')
},
computed: {
posts() {
return this.$store.getters.getPosts
}
},
methods: {
render() {
console.log(this.comments)
}
},
mounted() {
setTimeout(() => {
this.render()
}, 2000);
},
}
store.js
export const store = new Vuex.Store({
state: {
posts: []
},
getters: {
getPosts (state) {
return state.posts
}
},
mutations: {
retrievePosts (state, comments) {
state.posts = posts
}
},
actions: {
retrievePosts (context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token
axios.get('/posts')
.then(response => {
context.commit('retrievePosts', response.data)
})
.catch(error => {
console.log(error)
})
}
}
})
It is because axios request is still processing when Vue invokes mounted hook(these actions are independent of each other), so state.posts are undefined as expected.
If you want to do something when posts loaded use watch or better computed if it's possible:
export default {
created() {
this.$store.dispatch('retrievePost')
},
computed: {
posts() {
return this.$store.getters.getPosts
}
},
methods: {
render() {
console.log(this.comments)
}
},
watch: {
posts() { // or comments I dont see comments definition in vue object
this.render();
}
}
}
P.S. And don't use render word as methods name or something because Vue instance has render function and it can be a bit confusing.

VueJS: Setting data initially based on http response

So I have a template .vue file:
<template>
<div id="app">
<textarea v-model="input" :value="input" #input="update"></textarea>
<div v-html="compiledMarkdown"></div>
</div>
</template>
<script>
var markdown = require('markdown').markdown;
export default {
name: 'app',
data() {
return {
input: '# Some default data'
}
},
mounted: function () {
this.$nextTick(function () {
this.$http.get(window.location.pathname + '/data').then((response) => {
this.input = response.body.markdown;
}) })
},
computed: {
compiledMarkdown: function() {
this.$http.post(window.location.pathname, {
"html": markdown.toHTML(this.input)}).then(function() {
},function() {
});
return markdown.toHTML(this.input);
}
},
methods: {
update: function(e) {
this.input = e.target.value
}
}
}
</script>
In the mounted function I am trying to set input equal to the response of an HTTP request, but when you view this file this.input is still the same as it was initially declared. How can I change this.input inside the compiledMarkdown function to be this.input in the mounted function. What other approaches might I take?
You can not call a async method from a computed property, you can use method or watcher to run asynchronous code, from docs
This is most useful when you want to perform asynchronous or expensive operations in response to changing data.
You have to ran that relevant code when input changes, like following:
var app = new Vue({
el: '#app',
data: {
input: '# Some default data',
markdown : ''
},
methods: {
fetchSchoolData: function (schoolId) {
var url = this.buildApiUrl('/api/school-detail?schoolId=' + schoolId);
this.$http.get(url).then(response => {
this.schoolsListData = response.data;
}).catch(function (error) {
console.log(error);
});
},
},
mounted: function () {
this.$nextTick(function () {
this.$http.get(window.location.pathname + '/data').then((response) => {
this.input = response.body.markdown;
})
})
},
watch: {
// whenever input changes, this function will run
input: function (newInput) {
this.$http.post(window.location.pathname, {
"html": markdown.toHTML(this.input)}).then(function() {
},function() {
this.markdown = markdown.toHTML(this.input);
});
}
},
Have a look at my similar answer here.