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.
Related
My apologies with this dumb question. I'm new to Vue and followed some tutorial on just setting it up and did it the way advised but now I don't see anything.
As said above, after importing and adding Vuex to my project, nothing is loaded on the page and there are no errors in the terminal while running the development server.
main.js
// ** if I comment these out then the page will load
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/store.js' // <-- **
Vue.config.productionTip = false
new Vue({
router,
store, // <-- **
render: h => h(App)
}).$mount('#app')
store.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
export default new Vuex.store({
state: {
user: '',
role: ''
},
mutations: {
},
actions: {
},
getters: {
}
})
if there is additional information needed then let me know
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.
How can I redirect to another vue page from my script code. I am using router.push() but cannot redirect to my desired vue page.
Following is my source code.
src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HomePage from '#/components/HomePage'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'IndexPage',
component: IndexPage
},
{
path: '/homepage',
name: 'HomePage',
component: HomePage
}
]
})
src/components/IndexPage.vue
<script>
import VueRouter from 'vue-router'
export default {
name: 'IndexPage',
methods: {
redirectUser() { // this method is called on button click
if (1 == 1)
{
router.push('/homepage');
//this.$router.push('/homepage');
}
}
}
}
</script>
After running this code I am getting error which states:
ReferenceError: router is not defined at eval
src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
window.Vue = Vue
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
Furthermore, I can access that same link from browser http://localhost:8080/#/homepage. But cannot redirect to it from my script code.
import Vue and VueRouter
and then call
Vue.use(VueRouter)
then in your method,
this.$router.push({name: 'HomePage'})
EDIT
You need to import both Vue and Vue Router if you want to use it in your code, that's why you are getting router is not defined at eval.
And also use
this.$router.push('/homepage');
Try this in your src/components/IndexPage.vue
<script>
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default {
name: 'IndexPage',
methods: {
redirectUser() { // this method is called on button click
if (1 == 1)
{
this.$router.push('/homepage');
}
}
}
}
</script>
Use your component instance property to access the router:
this.$router.push({name: 'HomePage'})
And do you have it in your app?
new Vue({
router,
render: h => h(App)
}).$mount('#app')
Thanx for the feedback friends. I was not importing my router file on my vue. The updated line of code is:
src/components/IndexPage.vue
<script>
import router from '../router/index.js' // Just added this line and code works !!
export default {
name: 'IndexPage',
methods: {
redirectUser() { // this method is called on button click
if (1 == 1)
{
router.push({name: 'HomePage'})
}
}
}
}
</script>
You can try the following code:
function redirect(page) {
window.location.href = page;
}
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>
I am creating a web app with Vue 2.x and Vuex 2.x. I am fetching some information from a remote location via an http call, I want that if that call fails I should redirect to some other page.
GET_PETS: (state) => {
return $http.get('pets/').then((response)=>{
state.commit('SET_PETS', response.data)
})
},
error => {this.$router.push({path:"/"}) }
)
}
But this.$router.push({path:"/"}) gives me following error.
Uncaught (in promise) TypeError: Cannot read property 'push' of undefined
How can this be achieved.
Simulated JsFiddle: here
import router from './router'
and use router.push
Simple like that.
This example may help you.
main.js
import Vue from "vue";
import VueRouter from "vue-router";
...
Vue.use(VueRouter);
export const router = new VueRouter({
mode: 'hash',
base: "./",
routes: [
{ path: "/", component: welcome},
{ path: "/welcome", component: welcome},
]
})
actions.js
import {router} from "../main.js"
export const someAction = ({commit}) => {
router.push("/welcome");
}
It looks like you aren't injecting your router into your app, hence it being 'undefined'
In previous versions of vue-router you would: Vue.use(VueRouter), with 2.0 you can inject the router into the app like below:
const routes = [
{ path: '/foo', component: Foo },
]
const router = new VueRouter({
routes
})
const app = new Vue({
router // inject the router
}).$mount('#app')
this should then make it available as this.$router throughout the app
Following answering a related question: How to use Vue Router from Vuex state? it seems that Vuex won't receive the router instance at this.$router. Therefore two methods were suggested to provide access to the router instance.
The first is more direct which involves setting a webpack global to the instance.
The second involves using Promises with your vuex action that would allow your components to utilise their reference to the router instance following the actions Promise resolving / rejecting.
INITIAL ANSWER
In main.js (the one, where we "install" all modules and create Vue instance, i.e. src/main.js):
const vm = new Vue({
el: '#app',
router,
store,
apolloProvider,
components: { App },
template: '<App/>'
})
export { vm }
This is my example, but in our case the most important here is const vm and router
In your store:
import { vm } from '#/main'
yourMutation (state, someRouteName) {
vm.$router.push({name: someRouteName})
}
P.S. Using import { vm } from '#/main' we can access anything we need in Vuex, for example vm.$root which is needed by some components of bootstrap-vue.
P.P.S. It seems we can use vm just when everything is loaded. In other words we can not use vm inside someMutation in case, if we call someMutation inside mounted(), because mounted() comes/occurs before vm is created.
NEW ANSWER
Constantin's answer (the accepted one) is better than mine, so just want to show for novice how to implement it.
Inside core dir (inside /src in my case), next to App.vue, main.js and others I have router.js with the content:
import Vue from 'vue'
import Router from 'vue-router'
// Traditional loading
import Home from '#/components/pages/Home/TheHome'
// Lazy loading (lazy-loaded when the route is visited)
const Page404 = () => import(/* webpackChunkName: "Page404" */ '#/components/pages/404)
const Page503 = () => import(/* webpackChunkName: "Page503" */ '#/components/pages/503)
Vue.use(Router)
const router = new Router({
mode: 'hash',
base: process.env.BASE_URL,
linkExactActiveClass: 'active',
routes: [
{
path: '*',
name: 'Page404',
component: Page404
},
{
path: '*',
name: 'Page503',
component: Page503
},
{
path: '/',
name: 'Home',
component: Home
},
// Other routes
{....},
{....}
]
})
// Global place, if you need do anything before you enter to a new route.
router.beforeEach(async (to, from, next) => {
next()
})
export default router
Import our router to main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
const vm = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
export { vm }
Finally, inside your component, or Vuex or anywhere else import router from './router' and do whatever you need, such as router.push(...)
I didn't like keeping my app's location state separate from the rest of my app state in the Store, and having to manage both a Router and a Store, so I created a Vuex module that manages the location state inside the Store.
Now I can navigate by dispatching actions, just like any other state change:
dispatch("router/push", {path: "/error"})
This has the added benefit of making things like animated page transitions easier to handle.
It's not hard to roll your own router module, but you can also try mine if you want to:
https://github.com/geekytime/vuex-router
You can simply import route from router directory like this:
import router from '#/router'
router.push({name: 'Home'})
this # symbol replaces the path to the src directory