I am new to Vuex and trying to use mapActions to fetch some data from my store, and send it into my component's template. I keep getting the error message
[vuex] unknown action type: getItemDetail but I don't know why.
In my store, the action I'm trying to dispatch is getItemDetail. My full store is
import fetch from './fetch';
const url = 'items';
const defaults = {
id: '',
rating: '',
type: '',
};
const state = { ...defaults, };
const getters = {};
const actions = {
getItemDetail ({ commit, }, itemId) {
fetch.get(`${url}/${itemId}`).then((response) => {
commit('setItemDetail', { ...defaults, ...response.data, });
});
},
};
const mutations = {
setItemDetail (state, item) {
state.item = item;
},
};
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};
In my component I have:
<template>
<div>
<p> {{ itemDetail }} </p>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
computed: {
itemDetail () {
this.getItemDetail('23451');
return this.$store.state;
},
},
methods: {
...mapActions([
'getItemDetail',
]),
},
};
</script>
Any help would be much appreciated!!!
From what I see of your code, you are in a namespaced store module.
To access a namespaced action, you need to map it with the name of the store module as the first parameter (the same should be applied for any mapState or mapGetter) :
methods: {
...mapActions("yourModuleName", [
'getItemDetail',
]),
},
Related
Creating a Vuejs application whereby I use Vuex for state management between the components.In Vuex store, I have an action that fetches some data from an API (which works fine) then populate it to the state (via a mutation). Next, I pass the updated state to the component using getters.
Am having a problem populating data to the state (reactive manner) from the action (via mutation). In the DOM when I log the getter am getting an empty string.
Vuex Store
const getDefaultState = () => {
return {
clientDeposit: ''
}
}
//state
const state = getDefaultState();
//getters
const getters = {
getDeposit: (state) => state.clientDeposit
}
//actions
const actions = {
fetchClients({ commit}) {
const clientId ="23"
axios.post('/api/motor/fetchClients', {
ClientId: clientId,
})
.then((response)=> {
//console.log(response); //returns data
const deposit = response.data;
commit('setDeposit', deposit);
})
}
}
//mutations
const mutations = {
setDeposit: (state, value) => (state.clientDeposit = value)
}
export default {
state,
getters,
actions,
mutations
}
Component
<template>
<div>
<button onclick="fetchClients()">Fetch Clients</button>
Deposit (Via computed property) : {{ fetchDeposit }}
Deposit (from getter) : {{ getDeposit }}
</div>
</template>
<script>
import { mapGetters , mapActions } from "vuex";
import axios from "axios";
export default {
name: "",
data() {
return {
}
},
computed: {
...mapGetters([
"getDeposit"
]),
fetchDeposit(){
return this.getDeposit
},
},
methods:{
...mapActions([
"fetchClients"
])
}
};
</script>
<style scoped>
</style>
I'm able to console data, as well as able to see data in vuex dev tool
but not able to display them in table. Please if someone could check
my code and tell me what is wrong with it. Thanks folks. I tried differents methods like async/await, promise, getters... but I was not able to to get the data, probably I was not calling it properly.
ROLE.VUE
<emplate>
<di>
<p v-for="(role, index) in roles :key="index">
</div>
</template>
<script>
import { mapState } from 'vuex'
export default ({
name: 'Role',
metaInfo: {
title: 'Role'
},
created () {
this.$store.dispatch('loadRoles').then((response) => { console.log(response) })
},
computed: {
...mapState([
'roles'
])
}
})
</script>
role.js
import Axios from 'axios'
export default {
// namespaced: true,
state: {
roles: [],
},
getters: {
roles (state) {
return state.roles
}
},
mutations: {
SET_ROLES (state, roles) {
state.roles = roles
}
},
actions: {
loadRoles ({ commit }) {
Axios.get('/settings/roles')
.then((response) => {
console.log(response.data)
// let roles = response.data
commit('SET_ROLES', response.data.roles)
})
}
}
}
index.js
import role from './role'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
},
mutations: {
//
},
modules: {
role
},
actions: {
//
}
})
Main.js
import { store } from './store/store'
new Vue({
router,
store,
ValidationProvider,
render: h => h(App)
})
When loading from a module with mapState, you need to specify the name of the module you are loading from. Here is the proper syntax for your case:
...mapState('role', ['roles'])
The first argument is the module name, and the second is an array of state properties from that module.
I'm working on the time-honored Todo list feature using Vue, Vuex, and axios. I have the feature componentized between the
whole list itself (TodoList) and the individual rows (TodoRow).
Please note that I have abbreviated the code snippets below to eliminate properties and elements that are not essential to understanding this problem. I would not recommend running the code locally.
TodoList component
<template>
<dashboard-container
:header-title="'To-Do-List'"
>
<div slot="action-buttons">
<add-new-button
v-if="!emptyTodos"
:disabled="isCreating"
class="pull-right"
#click="addNewTodo"
/>
</div>
<transition slot="container-content" tag="div">
<div v-if="!emptyTodos">
{{ todos }}
<todo-row
v-for="(item, index) in todos"
:key="index" :id="item.id"
:text="item.description"
:status="item.status"
:completed="item.completed"
/>
</div>
<empty-list v-else #addClick="addNewTodo" />
</transition>
</dashboard-container>
</template>
<script>
import DashboardContainer from '#/components/Dashboards/DashboardContainer'
import TodoRow from '#/components/TodoList/TodoRow'
import AddNewButton from './AddNewButton'
import EmptyList from './EmptyList'
import { mapState, mapActions } from 'vuex'
export default {
components: {
DashboardContainer,
EmptyList,
TodoRow,
AddNewButton
},
computed: {
...mapState('planProfile', {
todos: 'todos'
}),
emptyTodos () {
return this.todos.length === 0
},
isCreating () {
return this.todos.some(todo => todo.status === 'created')
}
},
mounted () {
return this.dispatchAction({
actionName: 'planProfile/getTodos'
}).catch(err => {
console.log('decide how to route handle errors', err)
})
},
methods: {
...mapActions({
dispatchAction: 'dispatchAction'
}),
addNewTodo () {
this.todos.unshift({
text: '',
done: false,
status: 'new'
})
}
}
}
</script>
Here is what the feature (with the non-abbreviated code) looks like in my browser with a few todo items. I have dumped the todos just for
easy illustration of the raw data in the store.
Here is the abbreviated code for the todo item itself:
TodoItem component
<template>
<div #mouseover="showActions = true" #mouseout="showActions = false">
<div>
<div>
<label>
<input
:checked="done"
type="checkbox"
>
</label>
</div>
<div v-show="showActions">
<div
v-for="action in currentActions"
:key="action.name"
class="action-icon pull-right"
#click="handleActionClick(action.name)"
>
<svg-icon :svg-settings="action.icon" />
</div>
</div>
</div>
</div>
</template>
<script>
import makeMdsIcon from '#/utils/makeMdsIcon'
import CheckboxInput from '#/components/Inputs/CheckboxInput'
import { mapActions } from 'vuex'
export default {
components: {
CheckboxInput
},
props: {
id: {
type: Number,
default: null
},
status: {
type: String,
default: 'created'
},
completed: {
type: Boolean,
default: false
}
},
data () {
return {
showActions: false,
checkIcon: makeMdsIcon('check--s')
}
},
computed: {
done () {
return this.completed
},
isCreating () {
return this.status === 'new' || this.status === 'updating'
},
currentActions () {
const actions = {
new: [{
name: 'save',
icon: this.checkIcon
}]
}
return actions[this.status]
}
},
created () {
if (this.completed) {
this.status = 'done'
}
},
methods: {
...mapActions({
dispatchAction: 'dispatchAction'
}),
saveTodo () {
this.status = 'created'
return this.dispatchAction({
actionName: 'planProfile/createTodo',
data: {
description: this.text
}
}).catch(err => {
console.log('decide how to route handle errors', err)
})
},
handleActionClick (actionName) {
const handlers = {
save: this.saveTodo
}
const currentHandler = handlers[actionName]
return currentHandler()
}
}
}
</script>
When the saveTodo method is called and the underlying planProfile/updateStatusTodo action is called at the Vuex store level, the save persists on the backend and I can verify this when I refresh. However, as we can see from the TodoList component, the store is not updated when this happens:
Abbreviated Vuex store
import todoService from '#/services/todoService'
const state = {
todos: []
}
const actions = {
createTodo: {
handler ({ commit }, payload = []) {
const { description } = payload
return todoService.createTodo({ description })
.then(todoData => {
return commit('addTodo', todoData)
})
}
}
}
const mutations = {
addTodo (state, payload) {
/* The line below is just for demonstrative purposes for this question */
state.todos = state.todos.push({id: 9999, description: 'this is mock data for SO', completed: false})
}
}
export default {
namespaced: true,
state,
actions,
mutations
}
Why is the store not being updated when addTodo is called at the Vuex store level? I have already validated the procedure
for other todo operations (such as deleting a todo) whereby I delete the todo and this information is instantaneously communicated to the
TodoList component, why is the same not happening for creating new todos?
Flow:
Right before I am about to save via clicking on the checkmark next to the first item:
After clicking, item has been saved on the backend (which I can verify by refreshing), but it's not in the store since the todos have not changed (and also by inspection of the Vuex store in the Chrome developer console).
I'm doing a chart component that will be several times represented on a page.
For that, I'm using Vuex where I have the mutations / actions to get that date, and everything works fine.
In the graph component, in created () I call the action to make the request, and I want to pass the date to the chart.
The state comes as follows -
{
typeChart: [data],
typeChart2: [data2]
}
If I do console.log from the state it appears fine but if using the key returns undefined.
console.log(this.dataChart)
// log - { stacked: Array }
console.log(this.dataChart.stacked);
// log - undefined
The only way I found to pass the state to the chart was to do a timeout but I think that is not the best way to do this.
here's the code I have
component of page -
<template>
<stacked-chart
endpoint="endpoint"
chart="stacked"
:states="['state1', 'state2', 'state3']"
:keys="['key1', 'key2', 'key3']"
/>
</template>
component of chart -
<template>
<div class="box-content-white">
<div class="title"> Gráfico 1 </div> <!-- //! name for chart -->
<column-chart :data="data" :stacked="true" :colors="['#006837', '#FF0000', '#000']"></column-chart>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { mapActions } from 'vuex';
export default {
props: {
endpoint: String,
chart: String,
states: Array,
keys: Array
},
data() {
return {
data: []
}
},
created() {
this.fetchReporting({endpoint: this.endpoint, chart: this.chart, states: this.states, keys: this.keys, formData: { state: 'negotiation' }});
console.log(this.dataChart);
console.log(this.dataChart[this.chart]);
setTimeout(() =>{
this.data = this.dataChart[this.chart];
}, 150);
},
methods: {
...mapActions({
fetchReporting: 'fetchReporting'
})
},
mounted() {
this.data = this.dataChart[this.chart];
},
computed: {
...mapGetters({
dataChart: 'dataChart'
})
},
watch: {
}
}
</script>
file with vuex -
import axios from 'axios';
const state = {
dataChart: {}
}
const mutations = {
'ADD_DATA_CHART'(state, data) {
state.dataChart[data.key] = [];
[].forEach.call(data.states, (s, i) => {
let obj = {};
obj.name = s;
obj.data = [];
[].forEach.call(data.value, d => {
obj.data.push([d.name, d[data.keys[i]].toFixed(2)]);
});
state.dataChart[data.key].push(obj);
});
}
}
const actions = {
fetchReporting({state, commit}, response) {
axios.post(response.endpoint, response.formData)
.then(({data}) => {
commit('ADD_DATA_CHART', {key: response.chart, value: data, states: response.states, keys: response.keys})
}).catch(err => {
console.log(err);
});
}
}
const getters = {
dataChart: state => {
return state.dataChart;
}
}
export default {
state,
mutations,
actions,
getters
}
any suggestion?
You need to wait for you action fetchReporting to complete. Either by using async/await or by using promise/resolve
I have my mutation committed, but the currentCampaign state is not updated instead returns undefined. Below is the screenshot.
This is the store.
import Vuex from 'vuex'
import Vue from 'vue'
import axios from 'axios'
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
campaigns: '',
currentCampaign: ''
},
actions: {
getCampaigns ( {commit} ) {
axios
.get('/api/campaign/history')
.then((response) => {
commit('GET_CAMPAIGNS', {campaigns: response.data});
})
}
},
mutations: {
GET_CAMPAIGNS: (state, {campaigns}) => {
state.campaigns = campaigns
},
getCurrentCampaign (state, {campaign}) {
state.currentCampaign = campaign
}
},
});
I am calling the mutation from component method like so:
methods: {
markAsCurrent (campaign) {
this.$store.commit('getCurrentCampaign', campaign.id)
}
}
What I'm not doing right here?
Thats why you are destructuring a campaign var and passing a number to the mutations, not a object.
Try this
getCurrentCampaign (state, campaign) {
state.currentCampaign = campaign
}