I am hoping someone can help me out. I moved all my modules from the store/index.js file to a new store/events.js files to clean things up. I am having troubles getting the namespace right for the loadAll action from event.js. Not sure what I am missing here as I got followed some documentation and believe this should be right. I included App.js where I am trying to us "this.$store.dispatch('events/loadAll')" to get the loadAll action. You can see the loadCurrent action is also dispatched in similar fashion and works just fine. Any help would be appreciated.
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import snackbarModule from './snackbar';
import eventsModule from './events';
import usersModule from './users';
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
snackbar: snackbarModule,
eventNames: eventsModule,
users: usersModule
}
})
event.js
import Api from "../service/api"
export default {
namespaced: true,
state: {
eventNames: [],
},
mutations: {
SET_EVENTNAMES(state, eventNames) {
state.eventNames = eventNames
}
},
actions: {
async loadAll({commit}){
let response = await Api().get('/event-names')
let eventNames = response.data.data
eventNames.forEach(e => {
e.attributes.id = e.id
})
commit('SET_EVENTNAMES', eventNames.map(e => e.attributes))
}
}
}
App.vue
<script>
import { mapState } from 'vuex';
export default {
name: 'App',
created(){
this.$store.dispatch('events/loadAll');
this.$store.dispatch('users/loadCurrent');
},
computed: {
...mapState({
currentUser: state => state.users.currentUser,
snackbars: state => state.snackbar.snackbars
})
},
data: () => ({
drawer: null,
items: [
{ title: 'Schedule', icon: 'mdi-calendar-month', to: '/' },
{ title: 'Results', icon: 'mdi-calendar-check', to: '/Results' },
{ title: 'Points', icon: 'mdi-format-list-numbered', to: '/Points' },
{ title: 'About', icon: 'mdi-help-box', to: '/About' },
],
}),
methods: {
logoutUser() {
this.$store.dispatch("users/logout");
}
},
}
</script>
I can see the following row in the index.js:
import eventsModule from './events';
But you listed the event.js file. Is this a typo? Have you listed the content of the events.js?
If you want to call the action as this.$store.dispatch('events/loadAll') you have to change the module name:
...
export default new Vuex.Store({
modules: {
snackbar: snackbarModule,
events: eventsModule, // <- change the key name to 'events'
users: usersModule
}
})
I think this question is already answered, although there are some note that i want to point out.
To improve your code readability, you should use the right helper. So a good practice to follow is the use of mapGetters and mapActions instead of using mapState.
So refactoring your code it would be like with Max corrections:
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
import snackbarModule from './snackbar';
import eventsModule from './events';
import usersModule from './users';
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
snackbar: snackbarModule,
events: eventsModule, // <-module name correction
users: usersModule
}
})
// events.js <- filename correction
import Api from "../service/api"
export default {
namespaced: true,
state: {
eventNames: [],
},
getters: {
GET_EVENTNAMES: (state) => state.eventNames // use getters instead of using state to prevent mutations in the state
},
mutations: {
SET_EVENTNAMES(state, eventNames) {
state.eventNames = eventNames
}
},
actions: {
async loadAll({commit}){
let response = await Api().get('/event-names')
let eventNames = response.data.data
eventNames.forEach(e => {
e.attributes.id = e.id
})
commit('SET_EVENTNAMES', eventNames.map(e => e.attributes))
}
}
}
// App.vue
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'App',
created(){
this.loadAll(); // called from methods/mapActions
this.loadCurrent(); // called from methods/mapActions
},
computed: {
...mapGetters({
currentUser: 'users/currentUser',
snackbars: 'snackbar/snackbars'
})
...mapGetters('events', [ // Can be used as an Array or as an Object
'GET_EVENTNAMES'
])
},
data: () => ({
drawer: null,
items: [
{ title: 'Schedule', icon: 'mdi-calendar-month', to: '/' },
{ title: 'Results', icon: 'mdi-calendar-check', to: '/Results' },
{ title: 'Points', icon: 'mdi-format-list-numbered', to: '/Points' },
{ title: 'About', icon: 'mdi-help-box', to: '/About' },
],
}),
methods: {
...mapActions('users', [ // Can be splited by modules or all together removing the module parameter ('users')
'logout',
'loadCurrent'
]),
...mapActions('events', [
'loadAll'
]),
logoutUser() {
this.logout(); // Can be used as an Array or as an Object
}
},
}
</script>
Related
Using vue 2 I'm trying to initialize data in vuex from a component before it loads. I can use the this.$store.dispatch and the action, along with its subsequent mutation, will run as expected from the created() function. If I call the same method in the created() function on the component using ...mapActions, the action and mutation in the module in the vuex store do not run as expected. I've looked at various ways to do this with namespacing the module (as it isn't the only module in this program), but I can't seem to get the method to run. It may be a timing in the lifecycle issue, but I'm not sure why created() wouldn't be appropriate. The addStage method is what I'm trying to have run to create the data in vuex to be displayed once the component that needs the data is loaded.
In a separate component (not shown here) I can use the ...mapActions helper by firing it from a button #click and it runs the addStage method from vuex just fine. What am I missing?
Component:
<template>
<div v-for="stage in getFlow.stages" :key="stage.id">
<flowstage v-for="step in stage.steps" :key="step.id">
<flowstep></flowstep>
</flowstage>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'flowbuildersub',
created(){
this.addStage;
//this.$store.dispatch('flowbuilder/addStage');
console.log("added stage");
},
methods: {
...mapActions('flowbuilder', ['addStage']),
},
computed: {
...mapGetters('flowbuilder', ['getFlow']),
}
}
</script>
Store:
import Vue from 'vue';
import Vuex from 'vuex';
import flowbuilder from './modules/flowbuilder.js';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
error: null,
loading: false,
information: null
},
getters: {
getError(state) {
return state.error;
},
getInformation(state) {
return state.information;
},
getLoading(state) {
return state.loading;
},
},
mutations: {
setInformation(state, payload) {
state.information = payload
},
setError(state, payload) {
state.error = payload
},
setLoading(state, payload) {
state.loading = payload
}
},
modules: {
flowbuilder
}
})
flowbuilder.js module:
export const state = {
flow: {
id: Math.ceil(Math.random()*100000000)+Math.floor(Date.now() / 1000),
name: null,
description: null,
modifiedBy: null,
stages: [],
},
};
export const getters = {
getFlow(state) {
return state.flow;
},
getStages(state) {
return state.flow.stages;
},
};
export const actions = {
addStage({ commit }) {
let defaultStep = {
id: 1,
type: "Assign",
data: null,
description: null,
subStep: null,
required: null,
selected: true,
};
let defaultStage = {
id: 1,
label: null,
description: null,
selected: false,
steps: [
defaultStep
],
};
console.log("made it here");
commit('ADDSTAGE', defaultStage);
},
};
export const mutations = {
ADDSTAGE(state, defaultStage) {
state.flow.stages.push(defaultStage);
console.log("added stage");
},
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
Hello my application starts growing so i decided to call in vuex(for the first time) but i can't get it to work when i call actions/mutations of a module
my taskModule
const state = () => ({
newTask : false,
tasks: []
})
const getters = {}
const actions = {
test() {
console.log('EYOOO IT WORKSS')
},
}
const mutations = {}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
my store
import { createStore } from 'vuex'
import taskModule from '../store/modules/tasks'
export default createStore({
state: {
taskModule
},
})
my component js
export default {
components: {
Button,
TaskList,
NewTask,
},
computed: mapState({
newTask: (state) => state.taskModule.state().newTask,
tasks: (state) => state.taskModule.state().tasks,
}),
methods: {
...mapActions("taskModule",["test"]),
newTask(val) {
this.$store.dispatch("taskModule/test")
console.log(val);
},
},
};
when i call newTask i get the error
Since you have a module you need to change :
export default createStore({
state: {
taskModule
},
})
To :
export default createStore({
modules: {
taskModule
},
})
https://next.vuex.vuejs.org/guide/modules.html
I have a simple doubt and is that I don't know why this works:
store/topics.js
export const state = () => ({
list:[]
})
import slugify from "limax"
export const mutations = {
ADD_TOPIC(state, title, subtitle){
state.list.push({
title,
subtitle,
id: Date.now(),
...
})
},
...
topics/new.vue
import {mapMutations} from 'vuex'
export default {
data(){
return {
title: '',
subtitle: '',
}
},
methods: {
addTopic(title, subtitle){
this.$store.commit('topics/ADD_TOPIC', title, subtitle)
},
...
And this, doesn't works:
store/topics.js
export const state = () => ({
list:[]
})
export const mutations = {
ADD_TOPIC(state, topic){
state.list.push(topic)
},
...
topics/new.vue
import {mapMutations} from 'vuex'
export default {
data(){
return {
topic: {
title: '',
subtitle: '',
id: Date.now(),
...
}
}
},
methods: {
addTopic(topic){
this.$store.commit('topics/ADD_TOPIC', topic)
},
...
The thing in the second case is that when I push a topic, it's pushed correctly in the array... But when I go to add the next one, is like a duplicate :S And when I write something in the inputs updates all duplicated objects of the array.
I was trying to pull data out of getters with a v-for but I kept getting nothing back so I decided to console log 'this.$store.getters.tiers' and it came back undefined.
The data shows up in the Vue Browser tab, but both State and Getters appear grayed out unless I manually click on that arrow. Is the blank data related to this, or something that I forgot in my code?
Thanks for the help!
import Vue from "vue";
import { mapGetters } from "vuex";
computed: {
tiers() {
return this.$store.getters.tiers;
},
...mapGetters(["loggedInUser"])
},
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: () => ({
tiers: [
{
id: 1,
name: "Director Subscription",
price: 25
},
{
id: 2,
name: "Regular Subscription",
price: 10
},
{
id: 3,
name: "Regular+ Subscription",
price: 15
}
],
StoreCart: []
}),
getters: {
tiers: state => state.tiers,
StoreCart: state => state.StoreCart
},
mutations: {
ADD_Item(state, id) {
state.StoreCart.push(id);
},
REMOVE_Item(state, index) {
state.StoreCart.splice(index, 1);
}
},
actions: {
addItem(context, id) {
context.commit("ADD_Item", id);
},
removeItem(context, index) {
context.commit("REMOVE_Item", index);
}
},
modules: {}
});
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn;
},
loggedInUser(state) {
return state.auth.user;
}
};
Edit: Figured it out!
I'm running Nuxt and after revising the docs, I realized that the framework already builds a lot of the objects that would otherwise need to be created when using vanilla Vuex. Below is the correct way to set up the store!
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const state = () => ({
tiers: [
{
id: 1,
name: "Director Subscription",
price: 25
},
{
id: 2,
name: "Regular Subscription",
price: 10
},
{
id: 3,
name: "Regular+ Subscription",
price: 15
}
],
StoreCart: []
});
export const mutations = {
ADD_Item(state, id) {
state.StoreCart.push(id);
},
REMOVE_Item(state, index) {
state.StoreCart.splice(index, 1);
}
};
export const actions = {
addItem(context, id) {
context.commit("ADD_Item", id);
},
removeItem(context, index) {
context.commit("REMOVE_Item", index);
}
};
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn;
},
loggedInUser(state) {
return state.auth.user;
},
tiers: state => state.tiers,
StoreCart: state => state.StoreCart
};
I have this component
<script>
const serviceName = 'events'
import { mapState } from 'vuex'
import crud from './mixins/crud'
export default {
mixins: [crud],
data() {
return {
serviceName: serviceName,
apiBaseUri: '/api/v1/' + serviceName,
}
},
computed: {
...mapState({
events: state => state.events.data,
}),
},
mounted() {
this.boot()
},
}
</script>
It defines a serviceName which I need to also use within this crud mixin:
import { mapActions, mapMutations, mapState } from 'vuex'
export default {
data: function() {
return {
loading: {
environment: false,
table: false,
},
}
},
computed: {
...mapState({
form: state => state.events.form,
environment: state => state.environment,
}),
},
methods: {
...mapActions(serviceName, ['load']),
...mapMutations(serviceName, [
'setDataUrl',
'setStoreUrl',
'setErrors',
'setFormData',
'storeFormField',
]),
isLoading() {
return this.loading.environment || this.loading.table
},
boot() {
this.setDataUrl(this.apiBaseUri)
this.setStoreUrl(this.apiBaseUri)
this.load()
},
back() {
this.$router.back()
},
storeModel() {
this.store().then(() => {
this.load()
this.back()
this.clearForm()
})
},
},
}
The problem is that I always get a "serviceName is not defined" error message, since serviceName is used in mapActions() and mapMutations().
The error occurs in
import crud from './mixins/crud'
And it completely ignores things like window.serviceName, which I also tried.
Simplest solution I can think of is move the serviceName definition to another file. For example...
// constants.js
export const SERVICE_NAME = 'events'
then you can import it where required, eg
// in your component, your mixin, etc
import { SERVICE_NAME as serviceName } from './constants'