Vuex module not accessible from rootState - vue.js

I needed to get route's query parameters inside Vuex in order to preload filter settings and update the state of the application. To make this possible I installed vuex-router-sync.
Next step was to synchronize the Vuex and VueRouter.
Router:
Vue.use(VueRouter);
export default new VueRouter({ mode: 'history' });
Store:
Vue.use(Vuex);
export default new Vuex.Store({
modules: { filters: FiltersModule },
plugins: [ FiltersPlugin ]
});
App's bootstrap:
const unsync = sync(store, router);
new Vue({
el: '#restaurant-admin-app',
components: {
'App': AppComponent,
'filters': FilterComponent,
'orders-table': OrdersTableComponent
},
store,
router
});
My FilterPlugin that should trigger the URL parsing:
export default store => {
store.dispatch('filters/parseURLFilterSettings');
}
And now, the funny part, here's the URL parsing action:
parseURLFilterSettings: ({ state, commit, rootState }) {
console.log('RootState:', rootState);
console.log('Route module (incorrect):', rootState.route);
console.log('Filters module (correct):', rootState.filters);
console.log('Object\'s keys:', Object.keys(rootState));
}
What am I doing wrong? I thought it might be something with syncing, but at the end the console.log shows clearly that the route Object is there (and it's not empty), but somehow when I access it, it's undefined. Thank you in advance.

The problem was very well explained here. What it basically says is that the object's value is evaluated when you open it's body in the console.
The problem was I didn't have the route module loaded yet, because I was trying to dispatch an action from a vuex plugin which seems to load before the vuex-router-sync's syncing was done.
The problem was solved when I moved application's bootstrap logic from vuex plugins into the AppRootComponent's mount lifecycle event.

You should import the router-sync. After that your store and routes wil behave properly. I usually do this in the main.js file.
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
sync(store, router)

Related

Using Vuex State in main js

I am trying to use my store state in main.js but it vanishes my component, can I use state in mian.js
Axios.defaults.headers.common['BranchId'] = this.$store.state.myBrachId,
if not what how can I set the default headers dynamically then..?
You're asking how to access a Vuex store outside a Vue component. The syntax that you're currently using is only valid if you're writing a Vue component.
In case you want to access Vuex outside (any .js file) you should, first, export the store. Then, import that store in your file and finally use the store as you place.
Let's see an example:
store/index.js
export const store = new Vuex.Store({
state () {
myBrachId: 'niceBranch007'
}
});
Then, in any other .js file (main.js in your case)
import { store } from 'store/index.js'
console.log(store.state.myBrachId)
If you're trying to add headers to axios I'd ask you to consider if you should really be getting that header data from a Vuex store anyways. Remember that any browser refresh will clear your store so you should not rely on it's availability more than you need to. Using localStorage or sessionStorage might be better for what you're looking to do here.
I am doing this right now this is my store
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
branchId: "",
},
getters:{
},
mutations: {
},
actions: {},
modules: {}
});
In header cmponent
this.$store.state.branchId = this.Branches[index].branchId;
in main js
import Axios from 'axios'
import { store } from './store/index'
Axios.defaults.headers.common['BranchId'] = store.state.branchId;
this is not setting axios header, it comes empty

How to change the vuex-persist key option dynamically?

I am using the plugin: https://www.npmjs.com/package/vuex-persist, and it works great. But I am not sure that what I am trying to do will work.
My application has a module of authentication, and the user can create their own settings that are stored in vuex and localstorage. But since there will be different users there will be different settings and that is why each user will have different localStorage, that is why they need to have different name.
In that case I need to change the name of the key setting on the storage plugin dynamically, and I don't know how to do that. The setting for the plugin look like this
import Vue from 'vue'
import App from 'App.vue';
import Vuex 'vuex';
import VuexPersist from 'vuex-persist';
Vue.use(Vuex);
const vuexLocalStorage = new VuexPersist({
key: 'vuex' // I WANT TO CHANGE THIS DYNAMICALLY, how to do that?
storage: window.localStorage, // or window.sessionStorage or localForage
// Function that passes the state and returns the state with only the objects you want to store.
// reducer: state => state,
// Function that passes a mutation and lets you decide if it should update the state in localStorage.
// filter: mutation => (true)
})
const store = new Vuex.Store({
...
plugins: [vuexLocalStorage.plugin]
});
...
new Vue({
store,
el: '#app',
render: h => h(App)
});

Vue.js Vuex cannot access store in router

I've seen that this question have been asked a couple of time but I cannot find any good answer and don't understand why my code is behaving like this.
As said in the title I'm trying to import my store in the router to be able to use my getters on conditional and grant a user to access or not a route.
But as soon as i'm trying to import the store I get the following error:
[vuex] unknown action type: autoSignIn
this is coming from:
const vm = new Vue({
router,
store,
provide,
i18n,
render: handle => handle(App),
created () {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$store.dispatch('autoSignIn', user)
this.$store.dispatch('loadMatter')
this.$store.dispatch('loadFootprints')
this.$store.dispatch('loadMembers')
}
})
So I guess that when my app is starting the store hasn't loaded yet.
How can I workaround that I want to be able to use
store.getters.mygetter
Thank you very much
I think you need to import your store in your router file
I'm doing it like this:
import store from "#/store/index.js";
Are you using modules of vuex?
Can you share your store index file?
https://vuex.vuejs.org/guide/modules.html
If you are using modules of vuex, you should do this.$store.dispatch('module_name/action_name')
I have my store split into files
Vue.use(Vuex);
const store = new Vuex.Store({
state,
actions,
mutations,
getters,
plugins: [
process.env.NODE_ENV === 'development' && createLogger({ collapsed: false }),
].filter(Boolean),
});
export default store;

How to set up vuexfireMutations in Vuex store.js file

I am attempting to build a Vue.js application that utilizes Vuexfire in the store.js file. My store.js file looks something like this:
import Vue from 'vue'
import Vuex from 'vuex'
import { vuexfireMutations, firestoreAction } from 'vuexfire'
import { db } from '#/main'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
items: []
},
mutations: vuexfireMutations,
actions: {
setEvents: firestoreAction(context => {
return context.bindFirestoreRef('items', db.collection('dbItems'))
}),
},
})
I understand from the documentation that the .bindFirestoreRef() method is what binds Firestore to the Vuex store, while firestoreAction is a wrapper that injects .bindFirestoreRef() into the context object, so that it can be used as a method of the store (along the same lines as the commit method). The payload is then committed to mutations, while vuexfireMutations apparently handles the mutation of the state behind the scenes. Does this mean that vuexfireMutations is a method? What is the right term to describe vuexfireMutations? I really don't feel like the documentation explains very well what this imported item is. I'm just kind of having to guess that it is something that handles mutations, but what is the right term for it?

Populate router with external json

I would like to add routes from an external json file, which can change at runtime, to my Nuxt application. A similar topic can be found here.
I've overridden the default Nuxt router with my own implementation. If I import the routes async using axios + router.addRoutes(), I seem to loose the server side rendering. It seems like createRouter will have async support, but it's not in an official release of Nuxt yet.
How do I import a js/json file synchronously to my router.js below, so that I can populate the routes? I want to be able to configure the routes at runtime, so I don't want it to be a part of the bundle.
modules/router.js:
const path = require('path')
module.exports = function () {
this.nuxt.options.build.createRoutes = () => {}
this.addTemplate({
fileName: 'router.js',
src: path.resolve(`${this.options.srcDir}`, 'router.js')
})
}
nuxt.config.js:
modules: ['~/modules/router']
router.js:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export function createRouter () {
const router = new Router({
mode: 'history',
routes: [/* ... */]
})
return router
}
You could try with sync-request.
It is a NPM package aimed to perform synchronous web requests. It is available here.
Please note that, as stated in the documentation of the package itself, it is not suitable for production environment, probably because of application hanging in case of missing data.
So await would be an answer but I guess you already tried that? So, something like this.
const routeFile = await fetch('pathToTheJsonFile');
const routes = await routeFile.json();
In case you can't make the method async, as a workaround maybe use jQuery. I don't like this but if there's no other option, for now, use async: false in jQuery get.
jQuery.ajax({
url: 'pathToYourJsonRoutes',
success: function (result) {
},
async: false
});