Simulating a loading spinner before debounce - vue.js

does anyone know how can I execute the this.isLoading = true before the debounce in this method?
It was supposed to be a loading spinner that will be animated when making async call via axios.
methods: {
searchAdminUsers: _.debounce(function(query) {
this.isLoading = true
axios.get('api/searchEmployees?format=json', { params: { q:query } })
.then(response => {
let data = response.data.map(item => (
{ text: `${item.FIRSTNAME} ${item.LASTNAME} - ${item.POSITION}`, id: item.ID }
))
this.options = data
this.isLoading = false
})
.catch(error => {
console.log(error)
})
}, 250)
}

Create another method that changes this.isLoading, and invokes the debounces method.
methods: {
wrapSearchAdminUsers(query) {
this.isLoading = true
this.searchAdminUsers(query)
}
searchAdminUsers: _.debounce(function(query) {
axios.get('api/searchEmployees?format=json', { params: { q:query } })
.then(response => {
let data = response.data.map(item => (
{ text: `${item.FIRSTNAME} ${item.LASTNAME} - ${item.POSITION}`, id: item.ID }
))
this.options = data
this.isLoading = false
})
.catch(error => {
console.log(error)
})
}, 250)
}

Related

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);
});
},

Vuejs Vuex sometimes initial state not working Error: [Vue warn]: Error in render: "TypeError: Cannot read property 'Any_Variable' of undefined"

Other pages are working fine. Only facing issue with this file. May be I am coding wrong.
Store file is included in app.js file as other pages are working I have not included it.
Here Sometimes I get undefined MDU_Number. Sometimes it work fine. I am new to vue js.
Image of error that I am receving:
This is my vue template
<div class="card-body">
<div class="form-group row">
<label class="col-sm-4 col-form-label">MDU Number</label>
<div class="col">
<input
name="MDU_Number"
:value="mduprofile.MDU_Number"
#input="updateMDUNumber"
type="text"
class="form-control"
placeholder="Enter MDU Number Ex:GJXXCHXXXX"
required
/>
</div>
</div>
</div>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
};
},
created() {
this.fetchForMDU();
},
destroyed() {
this.resetState();
},
computed: {
...mapGetters("MDUSingle", [
"loading",
"country",
"area",
"product",
"mduprofile",
]),
},
methods: {
...mapActions("MDUSingle", [
"resetState",
"fetchForMDU",
"storeMDU",
"setMDUNumber",
]),
submitForm() {
this.storeMDU()
.then(() => {
this.resetState();
this.$eventHub.$emit(
"create-success",
"Created",
"MDU created successfully"
);
})
.catch((error) => {
console.log(error);
});
},
updateMDUNumber(e) {
this.setMDUNumber(e.target.value);
},
},
};
</script>
This is store file name single.js and I have included it in app.js file
MDU_Number should go for null value but it goes for undefined. So I think it is not initialized properly. There are many other variables but for simplicity purpose I have included only one.
What can be the issue?
function initialState() {
return {
mduprofile: {
MDU_Number: null,
},
country: [],
area: [],
product: [],
loading: false
};
}
const getters = {
country: state => state.country,
area: state => state.area,
product: state => state.product,
loading: state => state.loading,
mduprofile: state => state.mduprofile
}
const actions = {
fetchForMDU({ commit }) {
return new Promise((resolve, reject) => {
axios.get('/get/detail/for/mdu')
.then((response) => {
let detail = response.data;
commit('setCountryAll', detail.country);
commit('setStateAll', detail.state);
commit('setProductAll', detail.product);
}).catch(error => {
reject(error);
}).finally(() => {
resolve();
});
});
},
storeMDU({ commit, state, dispatch }) {
commit('setLoading', true);
dispatch('Alert/resetState', null, { root: true });
return new Promise((resolve, reject) => {
let params = _.cloneDeep(state.mduprofile);
axios.post('/save-mdu-profile', params)
.then((response) => {
resolve();
})
.catch(error => {
commit('setLoading', false);
let message = error.response.data.message || error.message;
let errors = error.response.data.errors;
dispatch('Alert/setAlert',
{ message: message, errors: errors, color: danger },
{ root: true });
reject(error);
}).finally(() => {
commit('setLoading', false);
});
});
},
fetchData({ commit }, value) {
axios.get('/mdu/profile/' + value)
.then((response) => {
commit('setAll', response.data.mdu);
}).catch(error => {
}).finally(() => {
});
},
updateMDU({ commit, state, dispatch }) {
commit('setLoading', true);
dispatch('Alert/setAlert', null, { root: true });
return new Promise((resolve, reject) => {
let params = _.cloneDeep(state.mduprofile);
axios.put('/update-mdu-profile/' + params.MDU_Id, params)
.then((response) => {
resolve();
}).catch(error => {
let message = error.response.data.message || error.message;
let errors = error.response.data.errors;
dispatch('Alert/setAlert',
{ message: message, errors: errors, color: danger },
{ root: true });
commit('setLoading', false);
reject(error);
}).finally(() => {
commit('setLoading', false);
});
});
},
resetState({ commit }) {
commit('resetState');
},
setMDUNumber({ commit }, value) {
commit('setMDUNumber', value);
}
}
const mutations = {
resetState(state) {
state = Object.assign(state, initialState());
},
setLoading(state, loading) {
state.loading = loading;
},
setCountryAll(state, items) {
state.country = items
},
setStateAll(state, items) {
state.area = items;
},
setProductAll(state, items) {
state.product = items;
},
setAll(state, items) {
state.mduprofile = items;
},
setMDUNumber(state, value) {
state.mduprofile.MDU_Number = value;
},
setCountry(state, value) {
state.mduprofile.Country = value;
},
setState(state, value) {
state.mduprofile.State = value;
},
setProduct(state, value) {
state.mduprofile.Product = value;
}
}
export default {
namespaced: true,
state: initialState,
getters,
actions,
mutations
}
Try checking somewhere where you change this values, if you don't catch error properly you may encounter empty states.

react native async getting data when running app first time

I have two components, in first components storing data in asyncstorage, in second component display data, when install app and save data does not get data from asyncstorage, when open app second time data are displayed.
storeData = async (item, messave, messrem) => {
const checkarary = this.state.favorite;
if(checkarary.some(e => e.name === item.name)) {
const value = this.state.favorite;
const position = value.filter((lists) => lists.id !== item.id);
this.setState({
favorite: position
}, () => {
try {
AsyncStorage.setItem('favoriti', JSON.stringify(this.state.favorite), () => {
Toast.show({
text: messrem,
buttonText: "Okay",
duration: 3000,
type: "danger"
});
});
} catch (error) {
}
});
} else {
this.setState({
favorite: [...this.state.favorite, item]
}, () => {
try {
AsyncStorage.setItem('favoriti', JSON.stringify(this.state.favorite), () => {
// AsyncStorage.getItem('favoriti', (err, result) => {
// console.log(result);
// });
Toast.show({
text: messave,
buttonText: "Okay",
duration: 3000,
type: "success"
});
});
} catch (error) {
}
});
}
};
Getting data in second component
_retrieveData = async () => {
try {
AsyncStorage.getItem('favoriti').then((value) => {
const parsed = JSON.parse(value);
this.setState({ favorite: parsed })
})
} catch (error) {
}
};
componentDidMount() {
this._retrieveData();
setTimeout(() => {
this.setState({
loading: false,
})
}, 2000)
};
componentDidUpdate() {
this._retrieveData();
};
How fix this issue, is there some solution. Can I set Item and reload app when install app or somthing else.
Use this
componentWillMount() {
this._retrieveData();
setTimeout(() => {
this.setState({
loading: false,
})
}, 2000)
};
instead of
componentDidMount() {
this._retrieveData();
setTimeout(() => {
this.setState({
loading: false,
})
}, 2000)
};
As componentWillMount is called after constructor is called for class and componentDidMount is called after screen is once rendered.

Pusher chatKit onMessage hook fails in Expo app

I am using React Native with Expo, and I am able to create users + rooms and send messages to them with the following code:
const hooks = {
onMessage: message => {
console.log("message", message);
this.setState({
messages: [...this.state.messages, message]
});
},
onUserStartedTyping: user => {
this.setState({
usersWhoAreTyping: [...this.state.usersWhoAreTyping, user.name]
});
},
onUserStoppedTyping: user => {
this.setState({
usersWhoAreTyping: this.state.usersWhoAreTyping.filter(
username => username !== user.name
)
});
},
onPresenceChange: () => this.forceUpdate()
};
class SetupChatKit extends React.Component {
constructor(props) {
super(props);
this.state = {
chatManager: null,
currentUser: {},
currentRoom: {},
messages: [],
usersWhoAreTyping: []
};
}
componentDidMount() {
const { userId, name } = this.props;
this.instantiateChatManager(userId);
this.createChatKitUser({ userId, name });
}
joinOrCreateChatKitRoom = (mode, chatKitRoomId, title) => {
const { chatManager } = this.state;
return chatManager
.connect()
.then(currentUser => {
this.setState({ currentUser });
if (mode === "join") {
return currentUser.joinRoom({ roomId: chatKitRoomId, hooks });
}
return currentUser.createRoom({
name: title,
private: false,
hooks
});
})
.then(currentRoom => {
this.setState({ currentRoom });
return currentRoom.id;
})
.catch(error => console.error("error", error));
};
instantiateChatManager = userId => {
const chatManager = new Chatkit.ChatManager({
instanceLocator: "v1:us1:9c8d8a28-7103-40cf-bbe4-727eb1a2b598",
userId,
tokenProvider: new Chatkit.TokenProvider({
url: `http://${baseUrl}:3000/api/authenticate`
})
});
this.setState({ chatManager });
};
My problem is that console.log("message", message); never gets called, even when I manually add messages to the room via the online control panel.
I've tried logging from chatManager, and that looks like the following:
As you can see from the documentation, the onMessage hook needs to be attached on subscribeRoom, not when joining a room.
https://docs.pusher.com/chatkit/reference/javascript#connection-hooks
So probably add subscribeToRoom() after the first success promise in your joinOrCreateChatKitRoom() method.
I refactored the code with async/await and used .subscribetoRoom() like so:
joinOrCreateChatKitRoom = async (mode, chatKitRoomId, title) => {
const { chatManager } = this.state;
try {
const currentUser = await chatManager.connect();
this.setState({ currentUser });
let currentRoom;
if (mode === "join") {
currentRoom = await currentUser.joinRoom({
roomId: chatKitRoomId
});
} else {
currentRoom = await currentUser.createRoom({
name: title,
private: false
});
}
this.setState({ currentRoom });
await currentUser.subscribeToRoom({
roomId: currentRoom.id,
hooks: {
onMessage: message => {
this.setState({
messages: [...this.state.messages, message]
});
},
onUserStartedTyping: user => {
this.setState({
usersWhoAreTyping: [...this.state.usersWhoAreTyping, user.name]
});
},
onUserStoppedTyping: user => {
this.setState({
usersWhoAreTyping: this.state.usersWhoAreTyping.filter(
username => username !== user.name
)
});
},
onPresenceChange: () => this.forceUpdate()
}
});
return currentRoom.id;
} catch (error) {
console.error("error creating chatManager", error);
}
};

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()
})
})