Vue2 - change the route based on store value - vue.js

I am trying to change the route of my components based on a value saved within the vuex store. There are four different template files, saved within different directories (template1, template2 etc). I am pulling the template id from the details store and depending on this value would like to render the component from the correct directory.
For example, if the template value in the store is 2 then load all the template2/profile component, if it is three load the template3/profile component.
import VueRouter from 'vue-router'
import store from '../store';
Vue.use(VueRouter)
const setComponent = componentName => {
return () => import(`../template${store.getters['detailsStore/getTemplate']}/views/${componentName}`)
}
const routes = [
{
path: '/',
redirect: '/details'
},
{
path: '/profile',
name: 'Profile',
//component: () => import('../template2/views/Profile') // - this is how i was importing the component but couldn't access vuex store
component: () => setComponent('Profile'),
},
{
path: '/details',
name: 'Details',
component: () => setComponent('Details'),
}
];
const router = new VueRouter({
mode: 'history',
routes
})
export default router
I thought creating the setComponent function would help,. but i just get a blank page. Any help would be much appreciated

Vue2:
Your component is not done loading. This will do it:
const asyncComp = async (componentName) => {
const component = await import(`../template${store.getters['detailsStore/getTemplate']}/views/${componentName}`)
return component;
};
{
path: '/profile',
name: 'Profile',
component: () => asyncComp('Profile'),
}
Vue 3 solution:
Here you will have defineAsyncComponent() available
https://vuejs.org/api/general.html#defineasynccomponent
const asyncComp = (compName) => defineAsyncComponent(() => import(`../template${store.getters['detailsStore/getTemplate']}/views/${compName}`);

Related

How to use createAsyncComponent in VueRouter#4.0.0 (Vue3)?

When I fill the component field in createRouter() like this:
{
path: '/article/post',
name: 'article-post',
component: defineAsyncComponent({
loader: () => import('#/views/article-post/index.vue'),
loadingComponent: () => import('#/views/article-post/skeleton.vue'),
}),
},
Seems like it's not working.
What I want it to show a loading page when the actual page is loading.
How do I do that?
The loadingComponent value must be a component definition, and cannot itself be an async component:
import { createRouter } from 'vue-router'
import { defineAsyncComponent } from 'vue'
import Skeleton from '#/views/article-post/skeleton.vue'
export default createRouter({
routes: [
{
path: '/article/post',
name: 'article-post',
component: defineAsyncComponent({
loader: () => import('#/views/article-post/index.vue'),
//loadingComponent: () => import('#/views/article-post/skeleton.vue'), ❌ cannot be dynamic import
loadingComponent: Skeleton ✅
}),
},
]
})
Also note that the loading component (Skeleton) is only shown once, i.e., if the component definition is not already in cache. This Codesandbox adds an artifical delay in loader() to demonstrate.
You can load components asynchronously like this:
{
path: '/article/post',
name: 'article-post',
component: () => ({
component: import('#/views/article-post/index.vue')
loading: import('#/views/article-post/skeleton.vue')
})
},
Note
Do not use Async components for routes. Async components can still be used inside route components but route component themselves are just dynamic imports.

Accessing to store in the router

I would like to check in my Vuex store whether a user has the 'admin' role before entering the /dashboard route. But I can't properly access data from store.getters.
I use Quasar (Vue.js) and Vuex + Typescript.
In the routes.ts file, on the beforeEnter() function, I can access getters from the store with a console.log(store.myStore.getters). Here I see userInfos inside:
I don't understand why I only get {} and not {...} (Note that if I click on it, I see its contents).
But if I call console.log(store.myStore.getters.userInfos), I don't see the data:
Here is index.ts (router):
import { route } from 'quasar/wrappers'
import VueRouter from 'vue-router'
import { Store } from 'vuex'
import { StateInterface } from '../store'
import routes from './routes'
export default route<Store<StateInterface>>(function ({ Vue }) {
Vue.use(VueRouter)
const Router = new VueRouter({
scrollBehavior: () => ({ x: 0, y: 0 }),
routes,
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
})
return Router
})
Here is routes.ts (router):
import { RouteConfig } from 'vue-router'
const routes: RouteConfig[] = [
{
path: '/',
component: () => import('layouts/Login.vue'),
children: [
{ path: '', component: () => import('pages/Index.vue') },
{ path: '/inscription', component: () => import('pages/SignUp.vue') },
{ path: '/connexion', component: () => import('pages/SignInPage.vue') }
]
},
{
path: '/main',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: '', component: () => import('pages/Index.vue') },
{ path: '/dashboard', component: () => import('pages/DashboardB2B.vue'),
beforeEnter: (to, from, next) => {
const store = require('../store')
console.log("before enter")
console.log(store.myStore.getters)
return next();
}, },
{
path: '/ajouter-un-referentiel',
component: () => import('pages/ReferentielMetier.vue')
},
{
path: '/init',
component: () => import('components/bot/BotSkeleton.vue')
}
]
},
{
path: '/bot',
component: () => import('layouts/Bot.vue'),
children: [
{
path: '/ajouter-un-referentiel',
component: () => import('pages/ReferentielMetier.vue')
},
{
path: '/init',
component: () => import('components/bot/BotSkeleton.vue')
}
]
},
// Always leave this as last one,
// but you can also remove it
{
path: '*',
component: () => import('pages/Error404.vue')
}
]
export default routes
And here is index.ts with the store (Vuex):
import Vue from 'vue'
import { store } from 'quasar/wrappers'
import Vuex from 'vuex'
Vue.use(Vuex)
import matching from './modules/matching'
import orga from './modules/organigrame'
import user from './modules/user'
export interface StateInterface {
example: unknown
}
let myStore: any
export default store(function({ Vue }) {
Vue.use(Vuex)
const Store = new Vuex.Store<StateInterface>({
modules: {
matching,
orga,
user
},
// enable strict mode (adds overhead!)
// for dev mode only
strict: !!process.env.DEBUGGING
})
myStore = Store
return Store
})
export {myStore}
EDIT: Looks like my console.log runs before the getters are loaded, because when I check out Vue developer tools, I see everything. How can I check the store if the store itself doesn't load before the beforeEnter function?
please try like this
store.myStore.getters["userInfos"]
I'm having exact issue, even if i use async/await :S
try this
router.beforeEach(async(to, from, next) => {
const userInfo = await store.getters.userInfos;
console.log(userInfo);
});

Vue js conditional statement inside axios fetch API

I have a vue-router like this
import Vue from 'vue';
import Router from 'vue-router';
import http from './helpers/http';
import Home from './views/Home/Home.vue';
import HomeMentor from './views/Home/HomeMentor.vue';
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: '',
component: () => import(/* webpackChunkName: "Container" */ './components/Container.vue'),
children: [
{
path: '/',
name: 'Dashboard',
component: {
render(c) {
http.request('GET', '/profile').then( async ({ data }) => {
console.log(data.profile.email)
if (data.profile.email === "vickysultan08#gmail.com") {
console.log('sip')
return c(HomeMentor);
} else {
return c(Home);
}
});
}
},
}
],
beforeEnter: isAuthentication,
}
});
The thing is, only the return component inside the conditional statement that cannot executed inside axios statement as the result below
While the return component inside the conditonal statement can be executed outside the axios statement like this
children: [
{
path: '/',
name: 'Dashboard',
component: {
render(c) {
a = 10
if (a === 10) {
console.log('sip')
return c(HomeMentor);
} else {
return c(Home);
}
}
},
}
],
I'm quite new in Vue JS and have to continue other person's code. Any advice?
Unfortunately, render functions must be synchronous.
What you may be able to do instead is simply use an async function to return the component, ala Async Components and Lazy Loading Routes.
const Dashboard = () => http.request('GET', '/profile').then(({ data }) => {
console.log('profile email', data.profile.email)
let isMentor = data.profile.email === 'vickysultan08#gmail.com'
let componentPath = `./views/Home/${isMentor ? 'HomeMentor' : 'Home'}.vue`
return import(componentPath) // chains in the "import" promise
})
and then in your route...
component: Dashboard,
If lazy-loading the component isn't working for you, you could always try pre-loading it
import http from './helpers/http';
import Home from './views/Home/Home.vue';
import HomeMentor from './views/Home/HomeMentor.vue';
const Dashboard = () => http.request('GET', '/profile').then(({ data }) => {
let isMentor = data.profile.email === 'vickysultan08#gmail.com'
return isMentor ? HomeMentor : Home
})

Redirect to specific url in case of wrong url in vuejs

I have two separate routing files where I am importing the component and defining their routing in each of its file and using it in index.js file. Here are my files code:
//router1.js
import Layout1 from 'Layouts/Panel.vue';
const Users = () => import('Views/Users.vue');
const Reports = () => import('Views/Reports.vue');
export default {
path: '/layout1',
component: Layout1,
redirect:'/layout1/reports',
children:[
{
path: 'reports',
component: Reports,
name:'Reports'
},
{
path: 'users',
component: Users,
name:'Users'
}
]
}
//router2.js
import Layout2 from 'Layout/Panel2';
const Demo1 = () => import('Views/Demo1');
const Demo2 = () => import('Views/Demo2');
export default {
path: '/',
component: Layout2,
redirect:'/demo1',
children:[
{
path: '/demo1',
component: Demo1
},
{
path: '/demo2',
component: Demo2
}
]
}
// index.js
import Vue from 'vue'
import Router from 'vue-router'
import router1 from './router1';
import router2 from './router2';
const NotFound = () => import('Views/NotFound.vue');
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
router1,
router2,
{
path: '*',
component: NotFound,
name:'NotFound',
},
]
})
Now, I want to redirect to specific url i.e "not-found" in case of wrong URL. In "NotFound" component I am adding below line of code in mounted lifecycle hook which redirects to URL "not-found".
this.$router.replace({ path: 'not-found' });
But if URL is having parameters or query string it will append to it. For e.g- http://localhost:8080/home/not-found
What I want is that it only shows http://localhost:8080/not-found How should I achieve this. Please help. Thanks!
try this in your mounted function. worked on my side.
this.$router.push({path: '/not-found'})

Route config "component" for path: / cannot be a string id

I am building routes into my website using vue-router, I am attempting to setup my route file the same way coreui does it. I am currently receiving the error "[vue-router] route config component" for path: / cannot be a string id. Use an actual component instead.
./src/router/index.js
import Vue from 'vue';
import Router from 'vue-router';
// Containers
const DefaultContainer = '../containers/DefaultContainer';
// Componenets
// const Navbar = '../components/Navbar';
// Views
const Home = '../views/Home';
const PageNotFound = '../views/404';
// Routes
Vue.use(Router)
export default new Router ({
mode: 'hash',
routes: [
{
path: '/',
redirect: '/home',
name: 'Home | Portfolio | Tom Dickson',
component: DefaultContainer,
children: [
{
path: 'home',
name: 'Home | Portfolio | Tom Dickson',
component: Home
}
]
},
{
path: '*',
component: PageNotFound
}
]
})
Well... Came back to it and was right in front of me:
Changed
// Containers
const DefaultContainer = '../containers/DefaultContainer';
To
// Containers
const DefaultContainer = () => import('../containers/DefaultContainer');
Then updated the rest of my views...