I need to populate a table using an array of objects got by an api call (axios). This part is working fine. In the store module (activity.js) I declared the array:
currentUserActivities: [],
In the mutations:
SET_CURRENT_USER_ACTIVITIES: (state, currentUserActivities) => {
state.currentUserActivities = currentUserActivities
},
In the actions:
setCurrentUserActivities({ commit }, userId) {
return new Promise((resolve, reject) => {
getUserActivities(userId).then(response => {
const currentUserActivities = response.results
commit('SET_CURRENT_USER_ACTIVITIES', currentUserActivities)
console.log('response current user activities: ', response.results)
resolve()
}).catch(error => {
console.log('Error setting single user activities: ', error)
reject(error)
})
})
},
Then I saved it in the getters module as so:
currentUserActivities: state => state.activity.currentUserActivities,
In the vue page, the relevant part of the script:
data() {
return {
currentUser: {},
userId: {
type: Number,
default: function() {
return {}
}
},
currentUserActivities: [],
}
},
mounted() {
const userId = this.$route.params.userId
this.$store.dispatch('user/setCurrentProfile', userId).then(() => {
const currentUser = this.$store.getters.currentProfile.user
this.currentUser = currentUser
console.log('user mounted user', currentUser)
this.$store.dispatch('activity/setCurrentUserActivities', userId).then(() => {
const currentUserActivities = this.$store.getters.currentUserActivities
console.log('activities on mounted', currentUserActivities)
})
})
},
In the template part, as I said, I will have a table data. Let's forget about it for now, I am just trying to get the array displayed raw, as so:
<div>
<p v-if="currentUserActivities.length = 0">
This user has no activities yet.
</p>
<p>CURRENT ACTIVITIES: {{ currentUserActivities }}</p>
<p>CURRENT USER: {{ currentUser }}</p>
</div>
The current user is displaying fine, in the browser I can see:
CURRENT USER: { "id": 1, "last_login": "20/09/2019 09:42:15", "is_superuser": false, "username": "admin", "first_name": "System", "last_name": "Dev", "email": "[email protected]", "is_staff": true, "is_active": false, "date_joined": "30/08/2019 09:03:40" }
The current user activities array, instead:
CURRENT ACTIVITIES: []
In the console I have both, leaving the user which is fine, the current user activities array is:
activities on mounted:
0: {...}
1: {…}
2:
activity: (...)
arrival_point: "SRID=4326;POINT (0 0)"
burns_calories: false
co2: "0.00"
co2_production: (...)
cost: (...)
created: (...)
default_cost: (...)
end: (...)
ecc. It's there, we can see it.
Inside the mounted, if we compare the code written for the user and the activities, the only difference is that I didn't set
this.currentUserActivities = currentUserActivities
If I do that, I loose the data in the console too (on the screen it remains empty array). In the console I would have:
activities on mounted: (5) [{…}, {…}, {…}, {…}, {…}, __ob__: Observer]
1. length: 0
2. __ob__: Observer {value: Array(0), dep: Dep, vmCount: 0}
3. __proto__: Array
Also, even if I set
v-if="currentUserActivities.length = 0"
to display a p tag in case the array is really empty, it doesn't get displayed. This too is not right. I don't know if they can be related.
I tried many many subtle different versions of code, but none of them worked.
I know I am missing something (code is never wrong....) ....
Can someone enlighten me, please?
Thanks a lot. x
First up, this:
this.$store.dispatch('activity/setCurrentUserActivities', userId).then(() => {
const currentUserActivities = this.$store.getters.currentUserActivities
console.log('activities on mounted', currentUserActivities)
})
As you've noted in the question, you aren't assigning currentUserActivities
to anything. It should be this:
this.$store.dispatch('activity/setCurrentUserActivities', userId).then(() => {
const currentUserActivities = this.$store.getters.currentUserActivities
this.currentUserActivities = currentUserActivities
console.log('activities on mounted', currentUserActivities)
})
I know you mentioned that this didn't work in the question but it is required to get it working. It isn't sufficient, but it is necessary.
The reason the array appears empty is because of this:
v-if="currentUserActivities.length = 0"
Note that you are setting the length
to 0, not comparing it to 0. It should be:
v-if="currentUserActivities.length === 0"
You've got some other problems too, though they're not directly related to the empty array.
Generally you shouldn't have data
values for state in the store (unless you're taking copies for editing purposes, which you don't seem to be). Instead they should be exposed as computed properties, e.g.:
computed: {
currentUser () {
return this.$store.getters.currentProfile.user
}
}
Vuex includes a helper called mapGetters
that can be used to shorten this a little, see https://vuex.vuejs.org/api/#component-binding-helpers, though some people prefer the explicitness of the longer form.
This is also a little strange:
return new Promise((resolve, reject) => {
getUserActivities(userId).then(response => {
Generally creating a new promise is regarded as a code smell as it is very rarely necessary. In this case you should probably just be returning the promise returned by getUserActivities
instead. e.g.:
return getUserActivities(userId).then(response => {
Obviously you'd need to make other adjustments to accommodate the resolve
and reject
functions no longer being available. Instead of resolve
you'd just return the relevant value (though there doesn't seem to be one in your case) and for reject
you'd just throw the error instead.
I also notice that userId
in your data
is being assigned a type
and default
. Note that this is prop syntax and isn't valid for data
properties. It isn't an error but the userId
will just be equal to that whole object, it won't treat it as a configuration object.