How to pass parameter in mapActions in vuex - vuex

I want to pass the parameter in mapAction in the computed property.
just like we can pass parameter in mounted.
this.$store.dispatch('GET_SUB_CATEGORIES', this.$store.getters.GET_BUSINESS_INFO.category_id)
I want to send parameter with mapAction
computed: {
...mapActions(['GET_SUB_CATEGORIES', ]),
},
in the computed property.

It's preety straight forward.
mutations: {
yourMutation (state, payload) {
state.yourParameter = payload
}
},
actions: {
mapThis (context, payload) {
context.commit('yourMutation', payload)
}
}

Related

How to trigger a Vue method when computed property changes

Essentially, in a Vue application, I have a page that lists Contacts. And a search form that is part of a header component. I capture the input search term as a state variable in the vuex store and track it as a computed variable.
I have a method to retrieve contacts that is called within the mounted hook. I want to call the same getContacts method again whenever the state search variable changes. Using a watcher to do this atm, but I have read that watching a computed value is not the right way. Wondering if there is a better way to do this. Script below.
<script>
import API from '#/utils/Api.js'
...
export default ({
...
tableData: [],
}
},
computed: {
search() {
return this.$store.getters.search;
}
},
mounted() {
this.getContacts();
},
methods: {
async getContacts() {
try {
const {data} = await API.get('/contacts?search=' + this.search)
this.tableData = data
} catch (e) {
console.error(e)
}
}
},
watch: {
search () {
this.getContacts();
}
}
})
</script>
Try to watch directly the state item and then pass the new value as parameter for the method, then use immediate:true to replace the mounted hook call :
export default ({
...
tableData: [],
}
},
methods: {
async getContacts(val) {
try {
const {data} = await API.get('/contacts?search=' + val)
this.tableData = data
} catch (e) {
console.error(e)
}
}
},
watch: {
'$store.getters.search': {
handler(newVal)
this.getContacts(newVal);
},
immediate:true
}
}
})

Unabled to use Vuex Getter with params

I have Vuex Store that will look like this
const config = {
featureA: { isEnabled: true, maxUser: 2 },
featureB: { isEnabled: false, maxData: 5 },
}
const actions = {
getDataCompany(context, payload) {
return new Promise(async (resolve, reject) => {
try {
const result = await firebase.firestore().collection(payload.collection).doc(payload.companyId).get()
if (result) {
if (payload.isLogin) await context.commit('setConfig', result.data())
return resolve(result.data())
}
reject(new Error('Fail To Load'))
} catch (e) {
reject(new Error('Connection Error'))
}
})
}
}
const mutations = {
setConfig(state, payload) {
state.config = payload
}
}
const getters = {
getData: ({ config }) => (feature, key) => {
const state = config
if (state) if (state[feature]) if (state[feature][key]) return state[feature][key]
return null
}
}
export default new Vuex.Store({
state: { config },
actions: { ...actions },
mutations: { ...mutations },
getters: { ...getters }
})
It's working fine with this method to get the data
computed: {
featureAEnabled() {
return this.$store.getters.getData('featureA', 'isEnabled')
},
}
But I have a problem when the data is change, the value is not update in component, and now I want to use mapGetters because it say can detect changes, But I have problem with the documentation and cannot find how to pass params here,
import { mapGetters } from 'vuex'
computed: {
...mapGetters({
featureAEnabled: 'getData'
})
}
I'am calling the action from here
async beforeMount() {
await this.$store.dispatch('getDataCompany', {collection: 'faturelsit', companyId: 'asep', isLogin: true})
}
And try to detect change in here
mounted() {
if (this.featureAEnabled) console.log('feature enabled')
}
The value change is not detected, and need to refresh twice before the changes is implemented in component
My main target is to detect if there any data change in Vuex and make action in component,
nevermind just working with watch without mapgetter,
I just realize that computed cannot re-run the mounted, so I make method that will called when the variable change in watch. thank you.
The main purpose is fulfilled, but the mapgetter with params is still not answered. so if anyone want to answer please share the way to use mapgetter with params.
You could try to use get and set methods for your computed property.
Example:
computed: {
featureAEnabled: {
get() {
return this.$store.getters.getData('featureA', 'isEnabled')
},
set(value) {
...update featureEnabled property in vuex store
}
},
}

Mutating Vuex array that is used in different component

In first component I have a function that changes the array using the value that is stored in VueX
methods: {
//get a function that changes the pickedlist array that is stored in vuex store
...mapActions([
'updatePickedDates'
]),
...mapGetters([
'dates'
]),
resetArray() {
this.updatePickedDates(this.dates}
}
In another component
I use getter from VueX that is passed on this array:
computed: {
...mapGetters(["managementNews"])
}
However when resetArray() function runs I get error that
state.pickedDates.includes is not a function
Here are the getters and mutations in my VueX store:
mutations: {
mutatePickedDates: (state, payload) => {
state.pickedDates=payload
}
},
actions: {
updatePickedDates({commit}, payload) {
commit('mutatePickedDates', payload)
}
},
modules: {
},
getters : {
//get news that are of type management
managementNews: function(state) {
return state.news.filter(i => i.type === "management" && state.pickedDates.includes(i.date));
},
dates: state => {
return state.dates
},
pickedDates: state => {
return state.pickedDates
}
},
In this case this.dates is a function and not an array. The error indicates that it's not undefined, yet it doesn't have includes method.
mapGetters should provide getters for computed properties. There's no way how mapGetters could be applied to methods and make this.dates to be an array.
It should be:
methods: {
...mapActions([
'updatePickedDates'
])
},
computed: {
...mapGetters([
'dates'
]),
}

VueJS: Computed Property Is Calculated Before Created in Component?

I have a component, which looks like this:
export default {
name: 'todos',
props: ['id'],
created () {
this.fetchData()
},
data() {
return {
}
},
computed: {
todos () {
return this.$store.state.todos[this.id]
}
},
methods: {
async fetchData () {
if (!this.$store.state.todos.hasOwnProperty(this.id)) {
await this.$store.dispatch('getToDos', this.id)
}
}
}
}
This is what's happening:
The component receives an id via props.
When the component loads I need to fetch some data based on the id
I have a created() hook from where I call a function fetchData() to fetch the data.
In methods, the fetchData() function dispatches an action to get the data. This gets and stores the data in Vuex store.
The computed property todos gets the data for this id.
The problem is that when the page first loads, the computed property todos shows up as undefined. If I change the page (client side) then the computed property gets the correct data from the store and displays it.
I am unable to understand why computed property doesn't update?
You could use following approach:
component.vue (and just render todoItem)
methods: {
async fetchData () {
const _this = this;
if (!this.$store.state.todos.hasOwnProperty(this.id)) {
this.$store.dispatch('getToDos', {id: this.id, callback: () => {
_this.todoItem = _this.$store.state.todos[_this.id]
}});
}
}
}
store.js
actions: {
getToDos: (context, payload) => {
// simulate fetching externally
setTimeout(() => {
context.commit("getToDos__", {newId: payload.id, task: "whatever" });
payload.callback();
}, 2000);
},
Base on here
When this hooks is called, the following have been set up: reactive data, computed properties, methods, and watchers. However, the mounting phase has not been started, and the $el property will not be available yet.
I think what might solve it is if you create a getter for todos.
So in your VueX Store add:
getters: {
todos(state) {
return state.todos;
}
};
And than in your computed use:
computed: {
todos () {
return this.$store.getters.todos[this.id]
}
}

How to update Vuex store from v-model input in case of v-for

I've say 10 objects in an array like
policies = [{name:'a',text:''},{name:'b',text:''},....]
They're iterated using v-for to show label A: Inputbox with text property binded as v-model.
I want to trigger a mutation whenever a policy's text changes in v-model.
Here's the fiddle link for it.
https://jsfiddle.net/dmf2crzL/41/
We assume you want to use v-model for a 2-way binding along with Vuex store.
Your problem is that you want Vuex store in strict mode.
const store = new Vuex.Store({
// ...
strict: true
})
so all of your mutation should go through Vuex store and you can see it in Vue.js devtools.
Method 1: We can avoid the Vuex error by using the cloned object and use watcher to commit the mutation.
const store = new Vuex.Store({
strict: true,
state: {
formdata: [
{ label: 'A', text: 'some text' },
{ label: 'B', text: 'some other text' },
{ label: 'C', text: ' this is a text' }
]
},
mutations: {
updateForm: function (state, form) {
var index = state.formdata.findIndex(d=> d.label === form.label);
Object.assign(state.formdata[index], form);
}
}
});
new Vue({
el: '#app',
store: store,
data () {
return {
//deep clone object
formdata: JSON.parse(JSON.stringify(this.$store.state.formdata))
};
},
computed: {
formdata() {
return this.$store.state.formdata
}
},
watch: {
formdata: function(form)
this.$store.commit('updateForm', form);
}
}
})
Method 2: You can use computed get/set to commit your mutation as per the vuex doc
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
another way that I found useful:
replace the v-model to a (v-on) function
that function triggers a mutation
the mutation ("function" in the store) change a value in state
a getter ("computed" in the store) "listens" to the change in the property value and changes accordingly.
this is an example of how to filter cards with Vuex (instead of v-model:
input that triggers a function "updateFilter":
<input type="text" placeholder="filter" v-on:input='updateFilter'>
a function (method) that triggers a mutation (commit):
methods: {
updateFilter(event){
this.$store.commit('updateFilter', event.target.value);
}
in the store.js, a mutation that changes data (state):
mutations: {
updateFilter (state, filter) {
state.filter = filter;
},
the state:
state: {filter: ""}
and the getter (computed) that "listens" to the change in the state.
getters: {
filteredGames: state => {
//your filter code here
return filtered;
})
},
and finally, the component that needs to be filtered has this computed (getter):
computed: {
filtered() {
return this.$store.getters.filteredGames;
}
Mine library vuex-dot simplifies reactivity (and, sure, v-model) usage on vuex store
https://github.com/yarsky-tgz/vuex-dot
<template>
<form>
<input v-model="name"/>
<input v-model="email"/>
</form>
</template>
<script>
import { takeState } from 'vuex-dot';
export default {
computed: {
...takeState('user')
.expose(['name', 'email'])
.dispatch('editUser')
.map()
}
}
</script>