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'
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
};
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>
When I'm trying to use the "getProducts" method through mapActions i am getting the "this.getProducts" is not a function.
Basically i get the actions from my product.js. So i don't know really why the error is existing.
I hope u can help me to handle with it. :)
My component ProductList.vue:
<script>
import ProductCard from "./ProductCard.vue";
import { mapState, mapActions } from "vuex";
export default {
components: {
ProductCard
},
computed: {
//state.modulname.state.js(products state)
...mapState("product" ["products"])
},
mounted() {
this.getProducts();
},
methods: {
...mapActions("product"["getProducts"])
}
};
</script>
<style>
</style>
My product.js File:
import store from "../../store/store";
import Product from "../../apis/Product";
const state = {
product: null,
products: [],
};
const mutations = {
SET_PRODUCT(state, product) {
state.product = product;
},
SET_PRODUCTS(state, products) {
state.products = products;
},
};
const actions = {
getProduct({ commit }, productId) {
Product.show(productId).then((response) => {
commit("SET_PRODUCT", response.data);
});
},
getProducts({ commit }) {
Product.all().then((response) => {
commit("SET_PRODUCTS", response.data);
});
},
};
const getters = {
getProductID() {
return (id) => state.products.filter((product) => product.id === id);
},
};
export default {
namespaced: true,
store,
state,
mutations,
actions,
getters,
};
Try this:
...mapActions([
'product/getProducts'
])
What is the best way to use this data from the Vuex store's Action in the needed component?
import axios from 'axios'
export default {
namespaced: true,
state: {
items: []
},
actions: {
fetchCategories ({state, commit}) {
return axios.get('/api/v1/categories')
.then(res => {
const categories = res.data
commit('setItems', {resource: 'categories', items: categories}, {root: true})
return state.items
})
}
}
}
Component
export default {
components: {
ThreadCreateModal,
ThreadList
},
data () {
return {
...
}
},
computed: {
...
},
created () {
...
},
methods: {
...
}
</script>
Where and how should I use that action for binding the data in this component?
Use mapState by import it from vuex and call it in computed:
computed: {
...mapState(['items']), // if you dont use namespace
...mapState("your_module_name", ['items'] ) // if you use namespace
},
then you can access it by this.items.
However, you can access it directly this.$store.state.items
I am trying to add the Actions I created in my Vuex module to the Methods of my component.
My component "HomePage.vue" looks like this
import { PlusIcon } from "vue-feather-icons";
import TaskItem from "../TaskItem";
import moment from "moment";
import { mapGetters, mapActions } from "vuex";
export default {
name: "home-page",
components: {
PlusIcon,
TaskItem,
},
methods: {
...mapActions(['fetchTasks'])
},
computed: mapGetters(['allTasks']),
created() {
setInterval(() => {
document.getElementById("time").innerHTML = moment().format("h:mm:ss a");
}, 1000);
},
};
My Vuex module "tasks.js" looks like this
import fs from 'fs'
const state = {
tasks: []
}
const getters = {
allTasks: (state) => state.tasks
}
const actions = {
fetchTasks({commit}) {
let rawdata = fs.readFileSync('../backend/tasks.json')
console.log(JSON.parse(rawdata))
commit('setTasks', JSON.parse(rawdata))
}
}
const mutations = {
setTasks: (state, passedTasks) => (state.tasks.push(passedTasks))
}
export default {
state,
getters,
actions,
mutations,
}
When attempting to use this.fetchTasks() in created(), nothing happens.
When console logging this.fetchTasks() it returns as undefined
Considering your tasks is a module of your vuex store, you should call your mapActions, mapGetters this way :
methods: {
...mapActions('tasks', ['fetchTasks'])
},
computed: {
...mapGetters('tasks', ['allTasks'])
},