I've got a little Vuex store (like below) and I use vuex-router-sync to keep it in sync. This adds a router module to my store, but how would I get this object out of the store as there don't seem to be any associated getters with this module?
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import module1 from './modules/module1'
import module2 from './modules/module2'
import module3 from './modules/module3'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
module1,
module2,
module3
}
})
main.js
import App from './views/App/App'
import store from './store'
import router from './router'
import { sync } from 'vuex-router-sync'
// sync router with store
sync(store, router)
new Vue({
el: '#app',
store,
router,
render: h => h(App)
})
My state would look something like this:
{
module1: {
cheese: true
},
module2: {
crackers: true
},
module3: {
wine: true
},
route: {
from: {}
fullPath:"/path/to/cheese"
hash:""
meta: {}
name:"cheese"
params: {}
path:"/path/to/cheese"
query: {}
}
}
Basically what I'm trying to do is add a title in my app header that updates depending on what page/view you are on.
Header.vue
export default {
name: 'header',
computed: {
getRouteTitle () => {
return this.$store.getters.getRouteTitle
}
}
}
Header.html
<header>
<h1>{{ getRouteTitle }}</h1>
</header>
Found a solution that works quite well. vuex-router-sync fires an action to telling us that the route has changed. Within one of our existing modules you can listen out of this and make a subsequent mutation. For me this would be setting the title from the router/ROUTE_CHANGED action payload.
router.js
const router = [
{
name: 'Cheese',
path: 'cheese',
component: Cheese,
meta: { title: 'Calendar', requiresAuth: true }
},
]
module1.js
import * as types from '../mutation-types'
// Initial State
const state = {
cheese: true,
title: 'App'
}
// Getters
export const getters = {
getRouteTitle: state => state.title
}
// Mutations
export const mutations = {
'router/ROUTE_CHANGED' (state, payload) {
state.title = payload.to.meta.title
}
}
export default {
getters,
mutations,
state
}
Hope that makes sense and please let me know if there is a better solution :)
******* UPDATE *********
A super easy way is just to get the $router instance in your component like this:
<h1>{{$route.name}}</h1>
Which would render to:
<h1>Cheese</h1>
Related
I am using azure application-insight to track events of a self-built search engine written within VUE.
I wrapped the application-insight SDK as a service and export a function.
import {
ApplicationInsights
} from '#microsoft/applicationinsights-web'
const appInsights = new ApplicationInsights({
config: {
instrumentationKey: "xxxx",
autoTrackPageVisitTime: true,
enableAutoRouteTracking: true,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true
}
})
appInsights.loadAppInsights();
appInsights.trackEvent();
export function useAppInsights() {
return appInsights
}
Then in my search-view page (search.vue), I call the service of application-insight and register two custom events to track.
`
<script>
import {
useAppInsights
} from '../services/AppInsights'
useAppInsights().trackEvent("search page loaded!");
useAppInsights().trackPageView({
name: 'search page'
});
export default {
methods: {
addQuery(key) {
useAppInsights().trackEvent({
name: 'SelectTag',
properties: {
searchInput: key
}
});
this.searchInput = key;
this.handleSearch();
},
}
};
</script>
The search.vue is integrated into the main.js using the router.
import Search from './components/Search.vue'
import Product from './components/Product.vue'
const routers = [{
path: '/search',
name: 'Search',
component: Search
},
{
path: '/product',
name: 'Product',
component: Product
},
]
export default routers
import Vue from "vue";
import VueRouter from "vue-router";
import "element-ui/lib/theme-chalk/base.css";
import routers from "./router";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import App from "./App.vue";
import axios from "axios";
Vue.config.productionTip = false;
Vue.use(VueRouter);
Vue.use(ElementUI);
Vue.use(axios);
const router = new VueRouter({
mode: "history",
routes: routers,
});
new Vue({
el: "#app",
router,
render: (h) => h(App),
});
The catalogue of my project is
But in my azure application-insight portal, I cannot see any events at all.
Does anyone have solutions to this condition? Many thanks!
I referred the following articles to realize trackevent codes:
https://dev.to/ardc_overflow/monitorando-uma-aplicacao-vuejs-com-o-application-insights-9h1
https://github.com/microsoft/applicationinsights-js#npm-setup-ignore-if-using-snippet-setup
In the second article, the sample of event tracking using application-insight is very clear:
appInsights.trackEvent({
name: 'some event',
properties: { // accepts any type
prop1: 'string',
prop2: 123.45,
prop3: {
nested: 'objects are okay too'
}
}
});
emmm...so I am trapped by the condition.
I want to perform a redirect, but before the redirect happens i want to perform a action using store.dispatch. Error is "store is not defined" in the console.
I have tried putting the whole line of code in a variable and check if true and if null, the error dissapears but the actions never gets called, and the debugger shows vue is jumping over the if-statement.
import Vue from 'vue'
import store from './store/index'
import Router from 'vue-router'
import Settings from './views/Settings.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/myPath',
name: 'myPathName',
component: {},
beforeEnter(to, from, next) {
//STORE is not defined
store.dispatch("path/MY_ACTION");
next({
name: "destinationPath",
})
}
}
-----------------------------------------------------------------------------
MY STORE
// STORE -> MODULES -> CONFIGURATION -> INDEX
import windowsModule from "../windows/index"
import mainDoorModule from "../maindoor/index"
import doorLeavesModule from "../doorleaves/index"
import doorModule from "../door/index"
import actions from "./actions"
import mutations from "./mutations"
export default {
namespaced: true,
modules: {
windows: windowsModule,
mainDoor: mainDoorModule,
doorLeaves: doorLeavesModule,
door: doorModule
},
state: {
configurationId: 0,
savedConfigurationsViewModel: [],
errors: {},
configurationsToSend: []
},
mutations,
actions
}
//THE ACTION I AM TRYING TO REACH INSIDE ACTIONS
// STORE -> MODULES -> CONFIGURATION -> ACTIONS
GET_DEFAULT_CONFIGURATION({ commit }) {
commit('SET_CONFIGURATION', {
//DATA
}
}
You need to install it in the main component. Then you refer to this through this.$store. Read the Vuex documentation.
export const store = new Vuex.Store({
state: {},
mutations: {},
getters: {}
})
import store from './store/index'
new Vue({
store, // <- here
el: '#app'
})
So it resolved. It was a Chrome bug saying that store is undefined, it's in webpack. Store was defined.
The problem was the mismatch between actions and mutations sending payloads that did not match types.
Thanks for all the answers, i appreciate it.
This problem is annoying me, i'm new with Vue and i'm trying to make a simple app to get practice.
Right now I'm using Vuex and Vue Router, here is the code:
The routes file, very simple, just a lazy load for the routes that aren't home.
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/tracks',
name: 'tracks',
component: () => import(/* webpackChunkName: "about" */ './views/Tracks.vue')
}
]
})
The view component, it just render the view childs:
<template>
<div id="tracks">
<logo></logo>
<search></search>
<songs></songs>
</div>
</template>
<script>
import Logo from '#/components/Logo.vue'
import Search from '#/components/Search.vue'
import Songs from '#/components/Songs.vue'
export default {
name: 'tracks',
components: { Logo, Search, Songs }
}
</script>
The songs component, this is the container where i make the logic (just list things right now)
<template>
<section id="track-list" class="columns is-centered">
<div class="column is-4" v-show="!songList.length">
<div class="notification is-danger">
No tracks loaded :(
</div>
</div>
</section>
</template>
<script>
import { mapState } from 'vuex'
import SongCard from './SongCard.vue'
export default {
name: 'songs',
components: { SongCard },
computed: {
...mapState([ 'songs' ])
}
}
</script>
I think the problem is in the rendering cycle, where the component is mounted the data isn't loaded yet, but this isn't async data (not mine, at least) but hardcoded in the state, initalized as empty array:
const state = {
songList: [ ],
song: null
}
// actions
const actions = {
}
// mutations
const mutations = {
// [tracks.GET_TOP](state, payload) {},
// [tracks.GET_TRACK](state, payload) {}
}
export default {
namespaced: true,
state,
actions,
mutations
}
Since i use Vuex, i don't use the data() {} key, else i use computed... what can i do here? I'm lost.
Edit, here is the complete store file:
import Vue from 'vue'
import Vuex from 'vuex'
import artists from './modules/artists'
import songs from './modules/songs'
import actions from './actions'
import mutations from './mutations'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
artists,
songs,
countries: {
state: {
selected: 'Mexico',
list: [
{ value: 'spain', name: 'España' },
{ value: 'mexico', name: 'México' },
{ value: 'argentina', name: 'Argentina' }
]
}
}
},
actions,
mutations
})
The main issue here is that songs is not a state, it's a namespaced module so it cannot be access directly like ...mapState(['songs']).
To map state of the songs module of the store, we use mapState helper syntax intended for use with namespaced module:
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
}
So, the correct syntax with respect to this question would be:
...mapState('songs', [ 'song', 'songList' ])
Note that you can also pass an object instead of array just like in the example above.
For more, refer this.
I have an issue with mutations in Vuex - In my component I have passed the getters and mutations, so that I can used the data. However, the getters are getting passed down just fine and can be retrieved from the component, but regarding the mutations, they all seem to be getting undefined. I have another component with identical setup, which seems to work fine.
Here is the code related to the component I have an issue with:
https://codesandbox.io/s/nlpvz0y6m
So far, I have tried retrieving the data by importing the whole store
but it isn't what I must do and not optimal.
Please advise further.
store:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
stats: {
controls: {
spin: false
}
},
getters: {
isSpinning: state => {
return state.controls.spin;
}
},
mutations: {
spinIt(state) {
return (state.controls.spin = !state.controls.spin);
}
}
}
});
component:
<template>
<div>
<div class="spin">
<span #click="spinIt">SPIN</span>
</div>
</div>
</template>
<script>
import {mapMutations} from 'vuex';
import {mapGetters} from 'vuex';
export default {
name: 'Stake',
computed: {
...mapMutations(['spinIt']),
...mapGetters(['isSpinning'])
}
}
</script>
First you need restructure the Vuex instance by the following:
export const store = new Vuex.Store({
state: {
stats: {
controls: {
spin: false
}
},
},
getters: {
isSpinning: state => {
return state.stats.controls.spin;
}
},
mutations: {
spinIt(state) {
return (state.stats.controls.spin = !state.stats.controls.spin);
}
}
});
Now you will access the getters and mutations.
After that, move the mapMutations into the methods block in your Spin.vue:
<script>
import {mapMutations} from 'vuex';
import {mapGetters} from 'vuex';
export default {
name: 'Stake',
computed: {
...mapGetters(['isSpinning'])
},
methods: {
...mapMutations(['spinIt'])
}
}
</script>
I created my store store/user.js
export const state = () => ({
user: {},
});
export const mutations = {
};
export const actions = {
AUTH ({commit},{email, password}){
console.log('email, password =', email, password)
}
};
export const getters = {};
component:
<template>
<form #submit.prevent="AUTH(model)">
<input type="text" required v-model.lazy = "model.email">
<input type="password" required v-model.lazy = "model.password" >
</template>
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
model:{
email:" " ,
password:" "
}
}
},
methods: {
...mapActions(['AUTH']),
}
}
In my component , I am trying to execute a vuex action from a module, but I am getting an error, even if this action is defined :
unknown action type: AUTH,
I don't have any idey about problem.
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user.js'
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
user
}
})
You need to use createNamespacedHelpers:
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('users')
Binding helpers with namespace
Otherwise, the mapping helpers need the full module namespace:
...mapActions([
'users/AUTH'
])
// if you are only using one module in the component
...mapActions('users', [
'AUTH'
])
Nuxt
You're mixing classic and modules mode. When using modules mode, Nuxt creates the store instance from the index.js file. You simply export the state, getters, mutations and actions. State should be exported as a function:
export const state = () => ({
foo: 0,
bar: 1
})
Any file within the store directory will be considered a module and Nuxt will automatically register it as a namespaced module.
- store
-- index.js // the store
-- users.js // module 'users'
-- foo.js // module 'foo'
The users module looks otherwise correct.
Make the following changes to your component:
// template
<form #submit.prevent="submitForm">
// script
methods: {
...mapActions({
auth: 'users/AUTH'
}),
submitForm () {
this.auth(this.model)
}
}