Vue/Bluebird: then callback doesn't run - vue.js

The then() for this.getStationsAsync() never runs. The catch() doesn't either, so there is likely nothing being rejected. Could I be doing something wrong with Promise.promisify(this.getStations)?
I have also tried this.getStationsAsync = Promise.promisify(this.getStations) inside the created() hook. I'm not getting any errors, but also not getting any console.logs() indicating that the then() executed.
import Vue from 'vue'
import axios from 'axios'
import Promise from 'bluebird'
methods:{
createStationMarkers (selectedNetworkMarker) {
this.selectedNetwork = selectedNetworkMarker
this.hideNetworkMarkers()
debugger
this.getStationsAsync()
.then(() => {
debugger
console.log('inside then')
this.addStationMarkers()
this.test = true
})
.catch(error => {
console.log(error)
})
}
},
getStations () {
axios
.get('/api/network/' + this.selectedNetwork.id)
.then(res => {
for (let station of res.data.stations) {
this.stations.push(station)
}
return res.data.stations
})
.catch(error => {
console.log(error)
})
}
}
computed: {
getStationsAsync () {
return Promise.promisify(this.getStations)
}
}

You need to return the result of the axios call, which is a promise.
getStations () {
return axios
.get('/api/network/' + this.selectedNetwork.id)
.then(res => {
for (let station of res.data.stations) {
this.stations.push(station)
}
return res.data.stations
})
.catch(error => {
console.log(error)
})
}
}
Bluebird is uneeccessary. Simply call getStations from createStationMarkers.

Related

How make Axios "finally" waiting until "then" is finished?

I'm trying to the finally be executed after the method getCharacters is finished, but without success.
He always is executed before.
There is a way to make him be executed after everything in the then is finished?
I suspect that the problem is the axios inside the getCharacters method.
new Vue({
el: '#app',
data () {
return {
message: '',
}
},
methods: {
getCharacters() {
axios
.get('/api/messages/characters')
.then(response => {
console.log('finish get')
})
},
submitForm: function (event) {
axios
.post('/api/messages/send', {
message: this.message
})
.then(response => {
this.getCharacters()
})
.finally(() => {
console.log('finish post')
})
}
}
})
You have to return the result of getCharacters:
.then(response => {
return this.getCharacters()
})
or
.then(response =>
this.getCharacters()
)

What is the function of this Vue "dispatch"?

I have this existing working VueJs code
const actions = {
retrieveStatus({ rootState, commit, dispatch }) {
return Axios
.get('/abc/GetStatus', {
params: {
draftId: rootState.eform.Id
}
})
.then(response => {
commit('SET_STATUS', response.data.statusCode);
return response.data;
})
.catch(err => {
throw new Error('Errors');
})
},
I don't see anywhere it uses dispatch but it exists there.

Mock .get() Function using Jest on VueJS

I am trying to mock a GET request to get some Posts using the ID. This is the code I am trying to mock:
getPost() {
this.refreshToken();
http
.get(`/posts/${this.$cookie.get('postid')}`, {
headers: {
"Authorization": `Bearer ${this.$cookie.get('token')}`,
"Content-type": "application/json",
},
})
.then((response) => {
this.post = response.data;
})
.catch((error) => {
console.log(error.response);
});
}
This is my attempt at a test:
import {getPost} from '#/views/Post.vue'
import axios from 'axios';
jest.mock('axios');
describe('get Post by ID', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should return empty when axios.get failed', async () => {
const getError = new Error('error');
axios.get = jest.fn().mockRejectedValue(getError);
const actualValue = await getPost();
expect(actualValue).toEqual(new Map());
expect(axios.get).toBeCalledWith('/posts/postid');
});
it('should return users', async () => {
const mockedUsers = [{ postID: 1 }];
axios.get = jest.fn().mockResolvedValue(mockedUsers);
const actualValue = await getPost(['1']);
expect(actualValue).toEqual(mockedUsers);
expect(axios.get).toBeCalledWith('/posts/postid');
});
})
The error I am getting is:
TypeError: (0 , _Post.getPost) is not a function
I am not sure what to do, and any help would be super appreciated. Thanks!
Assuming you have getPost() defined in the Post component's methods, you can't use named imports to access getPost. Instead, you'll have to mount the component, and use the wrapper's vm:
// Post.spec.js
import { shallowMount } from '#vue/test-utils'
import Post from '#/views/Post.vue'
it('...', () => {
const wrapper = shallowMount(Post)
await wrapper.vm.getPost()
expect(wrapper.vm.post).toEqual(...)
})
Also make sure to return the axios call in getPost() so that it could be awaited:
// Post.vue
export default {
methods: {
getPost() {
this.refreshToken();
👇
return http.get(/*...*/)
.then(/*...*/)
.catch(/*...*/);
}
}
}

Copy of store not updated when mounted Async axios

I have been struggling with this issue for a day now. I want to make a copy of the store for user into userCopy so that it can be edited by the user without causing a mutation. My problem is that even though I am using the mounted hook, userCopy only returns an empty store state.
pages/settings/_id.vue
<template>
<div>
{{ user }} // will display the whole object
{{ userCopy }} // will only display empty store object
</div>
</template>
<script>
import { mapState } from 'vuex'
import _ from 'lodash'
data() {
return {
userCopy: {}
}
},
computed: {
...mapState({ user: (state) => state.staff.user })
},
created() {
this.$store.dispatch('staff/fetchUser', this.$route.params.id)
},
mounted() {
this.$data.userCopy = _.cloneDeep(this.$store.state.staff.user)
},
</script>
store/staff.js
import StaffService from '~/services/StaffService.js'
export const state = () => ({
user: {
offers: '',
legal: ''
}
})
export const mutations = {
SET_USER(state, user) {
state.user = user
},
}
export const actions = {
fetchUser({ commit, getters }, id) {
const user = getters.getUserById(id)
if (user) {
commit('SET_USER', user)
} else {
StaffService.getUser(id) // StaffService users axios get call
.then((response) => {
commit('SET_USER', response.data)
})
.catch((error) => {
console.log('There was an error:', error.response)
})
}
},
}
export const getters = {
getUserById: (state) => (id) => {
return state.staff.find((user) => user.id === id)
}
}
Even using this mounted method did not solve the issue. The userCopy object still returns empty.
mounted() {
this.$store
.dispatch('staff/fetchUser', this.$route.params.id)
.then((response) => {
this.userCopy = this.$store.state.staff.user
})
},
It seems that the mounted() is called before your network request get solved.
To fix this, I suggest to do like this.
First:
if (user) {
console.log('user found',user)
commit('SET_USER', user)
return user
} else {
console.log('user not found')
//RETURN the Axios Call here
return StaffService.getUser(id) // StaffService users axios get call
.then((response) => {
commit('SET_USER', response.data)
//return the response here, after committing
return response.data
})
then in your component
mounted() {
this.$store
.dispatch('staff/fetchUser', this.$route.params.id)
.then((response) => {
console.log(response)
this.userCopy = response
})
}

VueJs. How to close pre-loader after data from server have been loaded

I use VueX in my VueJs app and I need to close pre-loader after I got an answer from server for 4 my get requests. I try to use callback function to change pre-loader state but it changes after requests STARTs, but I need to change pre-loader state after all requests SUCCESS. Below is my code:
Index.vue
<template>
<div class="index">
<div class="content-is-loading"
v-if="appIsLoading"></div>
<div v-else class="index__wrapper">
<navbarInner></navbarInner>
<div class="index__content">
<sidebar></sidebar>
<router-view></router-view>
</div>
<foo></foo>
</div>
</div>
</template>
<script>
import NavbarInner from './NavbarInner'
import Sidebar from './Sidebar'
import Foo from './../Foo'
import Shows from './Shows/Shows'
import Dashboard from './Dashboard'
import { API_URL } from '../../../config/constants'
import { mapState } from 'vuex'
export default {
name: 'index',
data () {
return {
appIsLoading: true,
bandName: ''
}
},
components: {
NavbarInner,
Sidebar,
Foo,
Shows,
Dashboard
},
created () {
function loadData (context, callback) {
// Loading bands for the user
context.$store.dispatch('getBands')
// Loading contacts for the user
context.$store.dispatch('getContacts')
// Loading merch for the user
context.$store.dispatch('getInventory')
// Loading tours for the active band
context.$store.dispatch('getToursList')
callback(context)
}
loadData(this, function (context) {
context.appIsLoading = false
})
}
}
Below I add code of one of the request:
api/tour.js
import axios from 'axios'
import { API_URL } from '../../config/constants'
export default {
getToursList () {
return new Promise((resolve, reject) => {
let bandId = window.localStorage.getItem('active_band_id')
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/bands/' + bandId + '/tours/', {
headers: {'x-access-token': token}
})
.then((result) => {
return resolve(result.data)
})
.catch(err => reject(err))
})
},
getInventory () {
return new Promise((resolve, reject) => {
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/merch/listProductForUser/1000/0', {
headers: {'x-access-token': token}
})
.then((response) => {
let items = response.data
return resolve(items)
})
.catch((err) => {
return reject(err)
})
})
},
getContacts () {
return new Promise((resolve, reject) => {
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/contact/get_contacts_for_user/1000/0', {
headers: {'x-access-token': token}
})
.then((response) => {
console.log(response.data)
let contacts = response.data
return resolve(contacts)
})
.catch((err) => {
return reject(err)
})
})
},
getBands () {
return new Promise((resolve, reject) => {
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/band/getBandsForUser/1000/0', {
headers: {'x-access-token': token}
})
.then((response) => {
console.log(response.data)
let bands = response.data
return resolve(bands)
})
.catch((err) => {
return reject(err)
})
})
}
}
Vuex/tour.js
import api from '../../api/onload'
import * as types from '../mutation-types'
const state = {
tours: [],
contacts: [],
bands: [],
merch: [],
success: false,
loading: false
}
const actions = {
getToursList ({commit}) {
api.getToursList()
.then((tours) => {
commit(types.RECEIVE_TOURS, tours)
}).catch((err) => {
console.error('Error receiving tours: ', err)
commit(types.RECEIVE_TOURS_ERROR)
})
},
getInventory ({commit}) {
api.getInventory()
.then((items) => {
commit(types.RECEIVE_INVENTORY, items)
})
.catch((err) => {
console.error('Error receiving inventory: ', err)
commit(types.RECEIVE_INVENTORY_ERROR)
})
},
getBands ({commit}) {
api.getBands()
.then((bands) => {
commit(types.RECEIVE_BANDS, bands)
})
.catch((err) => {
console.error('Error receiving bands: ', err)
commit(types.RECEIVE_BANDS_ERROR)
})
},
getContacts ({commit}) {
api.getContacts()
.then((contacts) => {
commit(types.RECEIVE_CONTACTS, contacts)
})
.catch((err) => {
console.error('Error receiving bands: ', err)
commit(types.RECEIVE_CONTACTS_ERROR)
})
}
}
const mutations = {
[types.RECEIVE_TOURS] (state, tours) {
state.tours = tours
},
[types.RECEIVE_INVENTORY] (state, items) {
state.items = items
},
[types.RECEIVE_BANDS] (state, bands) {
state.bands = bands
},
[types.RECEIVE_CONTACTS] (state, contacts) {
state.contacts = contacts
console.log(state.contacts)
}
}
export default {
state, mutations, actions
}
How should I change the code?
The code you posted doesn't actually wait on the response from any of the actions you are calling.
You could also move everything to a method and refactor.
Finally I've assumed your actions return a Promise i.e.
created () {
this.getAll()
},
methods: {
getAll () {
Promise.all([
this.$store.dispatch('getBands'),
this.$store.dispatch('getContacts'),
this.$store.dispatch('getInventory'),
this.$store.dispatch('getToursList'),
])
.then(responseArray => {
this.appIsLoading = false
})
.catch(error => { console.error(error) })
EDIT
To get your actions to resolve as you need them (when the mutations have fired and your store is updated) you need to wrap them in a Promise:
Vuex/tour.js (actions object)
getToursList: ({ commit }) =>
new Promise((resolve, reject) => {
api.getToursList()
.then((tours) => {
commit(types.RECEIVE_TOURS, tours)
resolve()
}).catch((err) => {
console.error('Error receiving tours: ', err)
commit(types.RECEIVE_TOURS_ERROR)
reject()
})
})