Vue Js paragraph display -> ok but checkbox doesn't works - api

I need call 3 times the same POST API call on mounted and get the response.
The response of api is stored on vuex.
If i do paragraph that works:
{{answer1}} // displayed 2
{{answer2}} // displayed 1
{{answer3}} // displayed 0
but my checkbox doesn't works on first launch but if i save my document and it re-render thats's works....:
<el-checkbox v-model="...." :disabled="answer1 > 0 ?'false':'true'" ></el-checkbox>
my mounted call api :
async mounted(){
await this.actionSetanswer1({
props1: '..',
props2: '..',
}).then(() => {
this.actionSetanswer2({
props1: '...',
props2: '...',
}).then(() => {
this.actionSetanswer3({
props1: '...',
props2: '...',
})
})
})
}
Thanks you very much in advance
NB : this.$forceUpdate() doesn't work too...

you can add a loading state:
// script
data() {
return {
isLoading: true
}
},
mounted() {
// ...
.then(() => {
this.actionSetanswer3({
props1: '...',
props2: '...',
}).then(() => {
this.isLoading = false
})
}
// template
<el-checkbox v-if="!isLoading" v-model="...." :disabled="answer1 > 0 ?'false':'true'" />

Related

Promise not waiting for store.dispatch

I've just started learning Vue, and am working on porting my django project to Vue. I started out simple. My objective is to create a component, which on loading, would use Axios to fetch a list of patients from my server.
So in my component, I wrote:
export default {
data() {
return {
patients: [],
};
},
created() {
console.log(`Created Component:Patient Waiting`);
this.$store
.dispatch("getPatientList", this.today)
.then(() => {
console.log(`Finished dispatch of getPatientList from component.`);
this.patients = this.$store.getters.patientNotSeenList;
console.log(`Now, this.patients is:`);
console.log(this.patients);
})
.catch((error) => {
console.log("Got error 2");
console.log(error);
});
},
};
Template:
<p v-for="patient in patients" :key="patient.checkinno">
{{ patient.checkinno }}
</p>
In my vuex store, I have:
export default createStore({
state: {
},
getters: {
patientNotSeenList: (state) => {
console.log(`In store, in getter:patientNotSeenList:`);
return state.patientNotSeenList;
},
},
mutations: {
STORE_PATIENT_LIST(state, data) {
state.patientSeenList = data.seen
state.patientNotSeenList = data.notseen
},
},
actions: {
getPatientList({ commit }, date) {
console.log(`[In Store::getPatientList, getting patient list...]`);
axios
.get(constants.API_GETPATIENT_LIST, {
params: {
....
},
})
.then(({ data }) => {
console.log(`Got data is`);
console.log(data);
let patientSeen = data.results.filter(
(checkin) => checkin.consulted == 1
);
let patientNotSeen = data.results.filter(
(checkin) => checkin.consulted == 0
);
console.log(`patientSeen is`);
console.log(patientSeen);
console.log(`patientNotSeen is`);
console.log(patientNotSeen);
console.log(`[Finished action for Store::getPatientList]`);
commit("STORE_PATIENT_LIST", {
seen: patientSeen,
notseen: patientNotSeen,
});
})
.catch((error) => {
console.log(
"In Store::getPatientList,Could not get data from API. Maybe not logged in, or dont have token?"
console.log(error);
)})
},
}
The problem I am having is that even though I am using a promise, the data is being rendered before the action is completed and mutation commited from store.
My console log looks like this:
Created Component: Patient Waiting
index.js?4360:141 [In Store::getPatientList, getting patient list...]
PatientWaiting.vue?110a:144 Finished dispatch of getPatientList from component.
index.js?4360:33 In store, in getter:patientNotSeenList:
PatientWaiting.vue?110a:146 Now, this.patients is:
PatientWaiting.vue?110a:147 undefined
TopBar.vue?92f9:90 Route location from TopBar: PatientWaiting
index.js?4360:150 Got data is
index.js?4360:151 {count: 1, next: null, previous: null, results: Array(1)}
index.js?4360:152 Results is
index.js?4360:153 [{…}]
index.js?4360:160 patientSeen is
index.js?4360:161 []
index.js?4360:162 patientNotSeen is
index.js?4360:163 [{…}]
index.js?4360:164 [Finished action for Store::getPatientList]
So I end up with an empty list. Why is this going wrong?
You are not returning the Promise axios.get(..).then(..) creates in getPatientList({ commit }, date) and thus the then() in your Component is immediately called. Change getPatientList to:
getPatientList({ commit }, date) {
console.log(`[In Store::getPatientList, getting patient list...]`);
return axios.get(constants.API_GETPATIENT_LIST, {
params: {
....
},
}).then(({ data }) => {
console.log(`Got data is`);
console.log(data);
let patientSeen = data.results.filter(
(checkin) => checkin.consulted == 1
);
let patientNotSeen = data.results.filter(
(checkin) => checkin.consulted == 0
);
console.log(`patientSeen is`);
console.log(patientSeen);
console.log(`patientNotSeen is`);
console.log(patientNotSeen);
console.log(`[Finished action for Store::getPatientList]`);
commit("STORE_PATIENT_LIST", {
seen: patientSeen,
notseen: patientNotSeen,
});
})
.catch((error) => {
console.log(
"In Store::getPatientList,Could not get data from API. Maybe not logged in, or dont have token?"
console.log(error);
)})
},

How to access query string in nuxtjs and pass it to data

I want to access query strings from url in nuxtjs page.
this is the page url with query strings -
http://localhost:3000/en-IN/atrsps/results/?pickupairport=Dubai&dropoffpoint=Bur%20Dubai,%20DU,%20United%20Arab%20Emirates&pickupdate=06%2F06%2F2021%2013%3A27
this is the my page script part
<script>
import axios from 'axios'
export default {
data() {
return {
cars: [],
loading: false,
disabled: true,
pickupairport: null,
dropoffpoint: null
}
},
asyncData({ route }) {
console.log(route.query)
},
computed: {
url() {
return `https://api.testdomain.com/V2/transfers/carlist?startpoint=${this.pickupairport}&endpoint=${this.dropoffpoint}&pickupdate=2021-07-01&pickuptime=14:55`
},
},
async created() {
await this.fetchData()
},
methods: {
async fetchData() {
this.loading = true //the loading begin
const res = await axios.get(this.url)
this.cars = res.data.response
this.loading = false
},
carsearch($state) {
setTimeout(() => {
axios
.get(this.url)
.then((res) => {
if (res.data.response.length > 1) {
res.data.response.forEach((item) => this.cars.push(item))
$state.loaded()
} else {
$state.complete()
}
})
.catch((err) => {
console.log(err)
})
}, 1000)
},
},
}
</script>
I want to pass pickupairport and dropoffpoint value from url to pickupairport & dropoffpoint in data.
in console, i can see this data
{
pickupairport: 'Dubai',
dropoffpoint: 'Bur Dubai, DU, United Arab Emirates',
pickupdate: '06/06/2021 13:27'
}
from the template you can access to it from $route object like $route.query and from the vue instance you can write this.$route.query
also you can check the $route object from vue dev tools. check out the picture below:
to pass the queries to data object you can just write:
data() {
return {
pickupairport: this.$route.query.pickupairport,
}
}
but you might not need to store the query in data object since you have access to $route object either from template or anywhere in your script

blink store data after change route

how can i avoid the data blink after update store data?
you can see the effect here:
https://drive.google.com/file/d/178raL6AJiC4bpIOImnaTKh6Yf9GruTCz/view?usp=sharing
component:
[...]
mounted() {
this.getIdeasFromBoard(this.$route.params.board_id);
},
[...]
store:
[...]
const actions = {
getIdeasFromBoard({ commit, dispatch }, board_id) {
apiClient
.get('/ideas/' + board_id)
.then((result) => {
console.log('success');
commit("SET_IDEAS_BOARD", result.data);
})
.catch(error => {
console.log('error' + error);
alert("You have failed to log in. Try again with another credentials.");
dispatch('auth/logout', null, { root: true });
this.$router.push({ name: "public" });
});
},
[...]
i've searched some simple tutorial about consuming api with error handling, but didnt find it.
thanks
It's because IDEAS_BOARD has the previous data until the new API call is completed. You would need to display a loader or a blank screen until the API call for the selected board is completed.
From actions, return a promise so that your component knows when is the call completed.
getIdeasFromBoard({ commit, dispatch }, board_id) {
return new Promise((resolve, reject) => {
apiClient
.get('/ideas/' + board_id)
.then((result) => {
console.log('success');
commit("SET_IDEAS_BOARD", result.data);
resolve()
})
.catch(error => {
console.log('error' + error);
alert("You have failed to log in. Try again with another credentials.");
dispatch('auth/logout', null, { root: true });
this.$router.push({ name: "public" });
reject()
});
})
},
In your .vue component,
async mounted () {
this.loading = true // some flag to display a loader instead of data
await this.$store.dispatch()
this.loading = false
}
There must be some other ways too like having this loading flag in the Vuex store. But it depends on you

How can I test data returned from an ajax call in mounted is correctly rendered?

I have a component (simplified)
<template>
<div v-if="account">
<h1 v-text="accountName"></h1>
</div>
</template>
<script>
import repo from '../../repo';
export default {
data() {
return {
account: {}
}
},
mounted() {
return this.load();
},
computed: {
accountName: function () {
return this.account.forename + ' ' + this.account.surname;
}
},
methods: {
load() {
return repo
.get(repo.accounts, {
params: {
id: this.$route.params.id
}
})
.then((response) => {
console.log(response.data);
this.account = response.data;
this.validateObj = this.account;
}, (error) => {
switch (error.response.status) {
case 403:
this.$router.push({name: '403'});
break;
default:
this.$refs['generic_modal'].open(error.message);
}
});
}
}
}
</script>
Which on mount, calls an API, gets the returned data, and renders the forename and surname.
I'm trying to write a mocha test to check that this works. I can do it using a timeout.
it('mounts', done => {
const $route = {
params: {
id: 1
}
};
mock.onGet('/api/accounts/1').reply(200, {
forename: 'Tom',
surname: 'Hart'
});
const wrapper = shallowMount(AccountsEdit, {
i18n,
mocks: {
$route
}
});
setTimeout(a => {
expect(wrapper.html()).toContain('Tom Hart');
done();
}, 1900);
});
But I wondered is there a better way? I was hoping to hook into the axios.get call, and run the check once that's finished, however, I can't seem to figure out how to do it.
EDIT: I tried using $nextTick, however, that didn't work either
wrapper.vm.$nextTick(() => {
expect(wrapper.html()).toContain('Tom Hart');
done();
});
{ Error: expect(received).toContain(expected) // indexOf
Expected substring: "Tom Hart"
Received string: "<div><h1>undefined undefined</h1></div>"
at VueComponent.<anonymous> (/home/tom/Dev/V6/Admin/.tmp/mocha-webpack/1554202885644/tests/Javascript/Components/Pages/account-edit.spec.js:37:1)
at Array.<anonymous> (/home/tom/Dev/V6/Admin/node_modules/vue/dist/vue.runtime.common.dev.js:1976:12)
at flushCallbacks (/home/tom/Dev/V6/Admin/node_modules/vue/dist/vue.runtime.common.dev.js:1902:14)
matcherResult: { message: [Function: message], pass: false } }
{ forename: 'Tom', surname: 'Hart' }
1) mounts
0 passing (2s)
1 failing
1) Accounts Edit Page
mounts:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/tom/Dev/V6/Admin/.tmp/mocha-webpack/1554202885644/bundle.js)
EDIT 2: It seems just as a test, chaining $nextTick eventually works, so I guess something else is causing ticks before my call returns? Is there anyway to tell what caused a tick to happen?
wrapper.vm.$nextTick(() => {
wrapper.vm.$nextTick(() => {
wrapper.vm.$nextTick(() => {
wrapper.vm.$nextTick(() => {
wrapper.vm.$nextTick(() => {
wrapper.vm.$nextTick(() => {
expect(wrapper.find('h1').html()).toContain('Tom Hart');
done();
});
});
});
});
});
});
Hey we had similar problem and found this library:
https://www.npmjs.com/package/flush-promises
Which allow to us wait all promises before continue testing.
Try to do something like this:
const flushPromises = require('flush-promises');
it('mounts', (done) => {
const $route = {
params: {
id: 1
}
};
mock.onGet('/api/accounts/1').reply(200, {
forename: 'Tom',
surname: 'Hart'
});
const wrapper = shallowMount(AccountsEdit, {
i18n,
mocks: {
$route
}
});
flushPromises().then(() => {
expect(wrapper.html()).toContain('Tom Hart');
done();
});
});

Missing requried props when using beforeEnter() route guard

I am trying to fetch data from API using beforeEnter() route guard but I am getting an error:
Missing required prop: "rides"
Here's my code.
router.js
{
path: '/',
name: 'home',
component: () => import('./components/main.vue'),
props: true,
beforeEnter(to, from, next) {
store.dispatch('ride/fetchRides').then(rides => {
to.params.rides = rides
next()
})
}
}
actions.js
fetchRides({ commit, dispatch }) {
return statistcsService.ridesForCurrentWeek()
.then(response => {
commit('SET_RIDES', response.data)
return response.data
})
.catch(error => {
const notification = {
type: 'danger',
message: 'There was a problem fetching your rides'
}
dispatch('notification/add', notification, { root: true })
throw error
})
}
Index.vue
<script>
export default {
props: {
rides: {
type: Array,
required: true
}
}
...
}
</script>
What am I missing? The prop is set in the component so am I not sure why it is crying.
I have verified that in 100% I am getting the data from API response.
You forgot to add rides property in your html code for that component. According to the error message - that's the problem.
Example:
<component :rides="rides"></component>