Nuxt Vuex State and Getters Has Data But Grayed Out - vue.js

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
};

Related

this.$store.dispatch works but ...mapActions does not

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 want to change count value by using v-model in vue app in vuex store

This code does not generate error but when I change my count it does not show the result on screen. Kindly help me in resolving the issue.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
lists: [
{
title: "User",
count: 15,
},
{
title: "Admin",
count: 41,
},
{
title: "Total Members",
count: 100,
},
{
title: "Manager",
count: 35,
}
]
},
mutations: {
updateMessage (state, count) {
state.lists.count = count
}
},
actions: {
},
modules: {
}
})
First thing, you don't need v-model to update your store. You can create a local copy and update it on the fly.
Second thing, I think you don't want to update not the whole counts of every objects but I guess you want to update an item in particular.
That's what I would do:
// 1. In component you watch state.lists and copy it immediately on init, deeply & on change:
data() {
return {
localCopyOfLists: []
}
},
watch: {
state.lists: {
immediate: true,
deep: true,
handler(v) {
this.localCopyOfLists = this.state.lists.map(x => (x))
}
}
}
// 2. Methods to change count of element in local list.
methods: {
updateItemInArray(index, count) {
this.localCopyOfLists[index].count = count
this.store.dispatch('SAVE_NEW_ARRAY', this.localCopyOfLists)
}
}
// 3. You update your store.
import Vue from 'vue'
export default new Vuex.Store({
actions: {
SAVE_NEW_ARRAY ({commit}, payload) {
commit('UPDATE_ARRAY', payload)
}
},
mutations: {
UPDATE_ARRAY (state, payload) {
Vue.set(state, lists, payload)
}
}
})

vuex unknown action type: events/loadAll

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>

Vuejs with namespaced modules and unknow mutation type

i have created two store modules and I did the import into main store.
When I load my drawer view, I am getting the next error.
What am I doing wrong here
error:vuex.esm.js [vuex] unknown mutation type: SET_DRAWER
//Drawer.vue
.........
computed: {
...mapState("navstore", ["barColor", "barImage"]),
drawer: {
get() {
return this.$store.state.navstore.drawer;
},
set(val) {
this.$store.commit("SET_DRAWER", val);
},
},
computedItems() {
return null;
//this.items.map(this.mapItem);
},
profile() {
return {
avatar: true,
title: "Gestan",
};
},
},
methods: {},
.........
.........
//store/index.js
import Vue from "vue";
import Vuex from "vuex";
import { default as auth } from ".auth";
import { default as navstore } from "./navStore";
Vue.use(Vuex);
export default new Vuex.Store({
modules: { auth: auth, navstore: navstore },
});
//navstore.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const SET_BAR_IMAGE = "NAVSTORE/SET_BAR_IMAGE";
const SET_DRAWER = "NAVSTORE/SET_DRAWER";
export default {
namespaced: true,
state: {
barColor: "rgba(0, 0, 0, .8), rgba(0, 0, 0, .8)",
barImage:
"https://demos.creative-tim.com/material-dashboard/assets/img/sidebar-1.jpg",
drawer: null,
},
mutations: {
[SET_BAR_IMAGE](state, payload) {
state.barImage = payload;
},
[SET_DRAWER](state, payload) {
state.drawer = payload;
},
},
actions: {
actionSetDrawer({ commit }, payload) {
commit(SET_DRAWER, payload);
},
},
};
//auth.js
import Vue from "vue";
import Vuex from "vuex";
import * as storage from "#/store/storage";
import services from "#/services/api/AuthenticationService";
Vue.use(Vuex);
const SET_USER = "AUTH/SET_USER";
const SET_TOKEN = "AUTH/SET_TOKEN";
export default {
namespaced: true,
state: {
token: null,
user: null,
isUserLoggedIn: false,
},
mutations: {
[SET_TOKEN](state, token) {
state.token = token;
state.isUserLoggedIn = !!token;
},
[SET_USER](state, user) {
state.user = user;
},
},
getters: {
isAuthenticated: (state) => !!state.token,
// authStatus: state => state.status
},
actions: {
actionDoLogin({ dispatch }, payload) {
return services.login(payload).then((res) => {
dispatch("actionSetUser", res.data.user);
dispatch("actionSetToken", res.data.token);
});
},
};
You need to remove prefixes with slash from mutation names because your modules namespaced and you will always access this mutations outside indicating a module name like this moduleName/mutation.
For instance:
const SET_BAR_IMAGE = "NAVSTORE/SET_BAR_IMAGE";
const SET_DRAWER = "NAVSTORE/SET_DRAWER";
// should be
const SET_BAR_IMAGE = "SET_BAR_IMAGE";
const SET_DRAWER = "SET_DRAWER";
Because the SET_DRAWER mutation is inside a navspaces module you should call it indicating a module name:
this.$store.commit("navstore/SET_DRAWER", val);
Don't try to call actions inside actions like this:
actionDoLogin({ dispatch }, payload) {
return services.login(payload).then((res) => {
dispatch("actionSetUser", res.data.user);
dispatch("actionSetToken", res.data.token);
});
},
Use mutations in a desired combination:
actionDoLogin({ dispatch }, payload) {
return services.login(payload).then((res) => {
commit(SET_USER, res.data.user);
commit(SET_TOKEN, res.data.token);
});
},

How do I use JSON data with vuex store (no webpack)

I managed to setup my first vuex store successfully.
An array of data is passed from the store to the desired component and rendered correctly.
Now I'd like to get my data from a JSON file, but cant get it to work.
I am not making use of a webpack, because sometimes I need to work on my project in an environment where these tools are not available.
The following, without retrieving data from a JSON file is working:
STORE.JS
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
products: [
{ name: "Avocado Zwem Ring", inventory: 47, unit_price: 77, image:"a.jpg", new:true },
{ name: "Danser Skydancer", inventory: 5, unit_price: 45.99, image:"a.jpg", new:true}
]
},
});
SHOP.VUE
<template>
<comp-products v-bind:products="products"></comp-products>
</template>
<script>
module.exports = {
components: {
'comp-products': httpVueLoader('components/comp-products.vue')
},
computed:{
products(){
return this.$store.state.products
}
}
}
</script>
I have tried the following but it does not render anything but also does not return an error.
STORE.JS
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
products: [],
},
mounted() {
axios
.get("json/products.json")
.then(response => {
this.products = response.data.products;
})
},
});
SHOP.VUE
<template>
<comp-products v-bind:products="products"></comp-products>
</template>
<script>
module.exports = {
components: {
'comp-products': httpVueLoader('components/comp-products.vue')
},
computed:{
products(){
return this.$store.state.products
}
}
}
</script>
products.json
{
"products":[
{
"sku":"1",
"name": "Danser Skydancer",
"inventory": 5,
"unit_price": 45.99,
"image":"a.jpg",
"new":true
},
{
"sku":"2",
"name": "Avocado Zwem Ring",
"inventory": 10,
"unit_price": 123.75,
"image":"b.jpg",
"new":false
}]
}
I am sure that the path to the json file and the setup of axios is correct because I managed to retrieve and render the json data without making use of the vuex store.
For setting variables in the store you should use mutations.
After setting up the store call your api and then call the mutation on the store with the resulted data.
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
products: [],
},
mutations: { //Mutations are like setters
SET_PRODUCTS: (state, products) => { //capitalization is good-practice for vuex-mutations
state.products = products;
}
}
});
const setProductToStore = () => {
axios
.get("json/products.json")
.then(response => {
store.commit('SET_PRODUCTS', response.data.products);
})
}
setProductToStore();
Something like this should work.
It's also possible to simply import a data.json file like so:
import data from './data';
export default new Vuex.Store({
state: {
test: data
}
});