Vue Lifecycle Hooks - only destroy data when Parent route changes - vue.js

I have an app that uses vue router where the parent User route has the children Details, Pay, and Assignments. I would like to load all of the data from vuex when the parent User page loads and keep it alive until the parent is destroyed.
However, if I add this to the User (parent) layout, data is destroyed when switching between children.
In user.vue
<router-view :user="user" />
and
destroyed() {
this.$store.dispatch('clearUserState')
console.log('destroyed')
}
In router
{
path: '/users',
name: 'users',
component: () => import('../views/Users/Users.vue'),
meta: {
requiresAuth: true
},
},
{
path: '/users/:id', redirect: '/users/:id/details',
name: 'userHome',
component: () => import('../views/Users/User.vue'),
meta: {
requiresAuth: true
},
children: [
{
path: '/users/:id/details',
name: 'userDetails',
component: () => import('../views/Users/UserDetails.vue'),
props: true,
meta: {
requiresAuth: true
},
},
{
path: '/users/:id/assignments',
name: 'userAssignments',
component: () => import('../views/Users/UserAssignments.vue'),
props: true,
meta: {
requiresAuth: true
},
},
{
path: '/users/:id/payroll',
name: 'userPayroll',
component: () => import('../views/Users/UserPayroll.vue'),
props: true,
meta: {
requiresAuth: true
},
},
]
},
If the lifecycle hook on the parent isn't the correct place to clear my user data, should it be with some sort of navigation guard? or a watcher?
Thanks!

Related

Vue Router addRoute blank at router-view

First, sorry for my bad english.
I'm learning about modular architecture / Folder By Feature in vue just like this
enter image description here
In user module I created a router like this
enter image description here
And add user's router to main router like this
enter image description here
Builder router is my apps routing after user logged in. And my main router is like this
enter image description here
What's happening is everything works fine when I access /dashboard or /about or other page that defined main router. And I click the /user router (it cames from user's module router) and it also work fine. But when I access /dashboard again. the router view show nothing (it is <!-- --> in dev console).
It's OK when access dashboard. Page displayed (white boxes)
enter image description here
Also OK in user module router
enter image description here
It became blank when I access /dashboard again
enter image description here
The structure of router-view
<router-view> Page Loader
<router-view> Module Loader (Index, Add, Edit)
This is my main router
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Builder',
component: Builder,
meta: {
requiresAuth: true
},
redirect: '/dashboard',
children: [
{
path: 'dashboard',
name: 'Dashboard',
meta: {
pageTitle: 'Dashboard',
requiresAuth: true
},
component: () => import(/* webpackChunkName: "dashboard" */ '../views/Dashboard.vue')
},
{
path: 'about',
name: 'About',
meta: {
pageTitle: 'About',
requiresAuth: true,
breadcrumb: [
{
label: 'About',
to: '/about'
}
]
},
component: () => import(/* webpackChunkName: "about" */ '#/views/About.vue')
},
]
};
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
Registering Route
import router from '../router/index'
import store from '../store/index'
const registerModule = (name, module: any) => {
if (module.store) {
store.registerModule(name, module.store)
}
if (module.router) {
module.router.forEach(item => {
router.addRoute('Builder', item)
})
}
}
export const registerModules = (modules: any) => {
Object.keys(modules).forEach(moduleKey => {
const module = modules[moduleKey]
registerModule(moduleKey, module)
})
}
User Module Route
const moduleRoute = [{
path: '/user',
name: 'User',
component: () => import(/* webpackChunkName: "user" */ '../user/Module.vue'),
meta: {
pageTitle: 'User Management Builder',
requiresAuth: true,
breadcrumb: [
{
label: 'User',
to: '/user'
}
]
},
children: [
{
path: 'list',
name: 'UserList',
meta: {
pageTitle: 'User Management',
requiresAuth: true,
breadcrumb: [
{
label: 'User',
to: '/user'
}
]
},
component: () => import(/* webpackChunkName: "user" */ '../user/views/Index.vue')
},
{
path: 'add',
name: 'UserAdd',
meta: {
pageTitle: 'User Add',
requiresAuth: true,
breadcrumb: [
{
label: 'User',
to: '/user'
}
]
},
component: () => import(/* webpackChunkName: "user" */ '#/modules/user/views/Add.vue')
}
]
}]
export default moduleRoute
Extra Note:
I'm using webpack too in case it it affects my problem
Any help please. Thank you in advance.

How to load a specific 'route' (vue-router) outside the main component (app.vue)?

I need to load a route outside the app.vue, I have a dashboard that works fine then I decided to implement a login which implied changing the app.vue, so after changing it I have the problem that my dashboard loads inside app.vue thus taking the styles of app.vue and completely deforming, so what now I need is to load outside of app.vue so it can work properly like it did before.
These are my routes:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'history', // to disappear the # in URL's
base: process.env.BASE_URL,
routes: [
//HOME
{
name: 'Home',
path: '/',
component: () => import('#/components/Home.vue'),
},
//LOGIN
{
name: 'Login',
path: '/login',
//component: () => import('#/views/login/Login'),
component: () => import('#/components/Login.vue'),
},
//REGISTER
{
name: 'Register',
path: '/register',
component: () => import('#/components/Register.vue'),
},
//DASHBOARD
{
//name: 'Dashboard',
path: '/dash',
name: 'dashboardd',
component: () => import('#/views/dashboard/Index'),
children: [
//CLIENTS
{
name: 'Clients',
path: '/Clients',
component:()=> import('#/views/clientss/Clientss')
},
//SALES
{
name: 'Sales',
path: '/sales',
component:()=> import('#/views/sales/Sales')
},
//NUEVA VENTA
{
name: 'Sales',
path: '/new-sale',
component:()=> import('#/views/sales/NewSale')
},
//productos
{
name: 'Productos',
path: '/products',
component:()=> import('#/views/articulos/Products')
},
//listar articulos
{
name: 'ListarArticulos',
path: '/articulos',
component:()=> import('#/views/articulos/ListarArticulos')
},
//crear articulo
{
name: 'CrearArticulo',
path: '/articulos/crear',
component:()=> import('#/views/articulos/CrearArticulo')
},
//editar articulo
{
name: 'EditarArticulo',
path: '/articulos/editar/:id',
component:()=> import('#/views/articulos/EditarArticulo')
},
// Dashboard
{
name: 'Dashboard',
path: '/dash',
component: () => import('#/views/dashboard/Dashboard'),
},
{
name: 'PROVEEDORES',
path: '/providers',
component: () => import('#/views/providers/Provider'),
},
{
name: 'USUARIOS',
path: '/users',
component: () => import('#/views/users/User'),
},
{
name: 'REPORTES',
path: '/reports',
component: () => import('#/views/reports/Report'),
},
// Pages
{
name: 'User Profile',
path: 'pages/user',
component: () => import('#/views/dashboard/pages/UserProfile'),
},
{
name: 'Notifications',
path: 'components/notifications',
component: () => import('#/views/dashboard/component/Notifications'),
},
{
name: 'Icons',
path: 'components/icons',
component: () => import('#/views/dashboard/component/Icons'),
},
// Maps
{
name: 'Google Maps',
path: 'maps/google-maps',
component: () => import('#/views/dashboard/maps/GoogleMaps'),
},
],
},
],
})
And I need to load the route named 'Dashboard' outside the App.vue. Because of my dashboard has his own styles and work properly when it is the only app running :
You can simply access the router from all components that are part of your Vue by using this.$router.
In Vue 2, you would need to call this.$router.push({name:'Dashboard'}) to instantly navigate to the route named 'Dashboard'.

Duplicate named routes definition Error even though all child routes names are different

I am getting this error [vue-router] Duplicate named routes definition: even though i have different route names. I tried searching for this issue in stackoverflow and google, but couldnot find solution to this issue.
My route.js file.
const routes = [
{
path: '/',
component: () => import('layouts/MainDashboard.vue'),
children: [
{
path: '', name: 'LandingPage', component: () => import('pages/LandingPage.vue'), meta: { requiresAuth: false }
},
{
path: '/product_details/:productId', name: 'ProductDetails', component: () => import('pages/ProductDetails.vue'), meta: { requiresAuth: false }
},
{ path: '/cart', name: 'Cart', component: () => import('../cart/ShoppingCart.vue'), meta: { requiresAuth: false } },
{ path: '/checkout', component: () => import('../cart/CheckoutComponent.vue'), meta: { requiresAuth: true } },
{ path: '/page/:cardTitle', component: () => import('../pages/ProductListPage.vue'), meta: { requiresAuth: false } },
{ path: '/account', name: 'Account', component: () => import('../account/AccountComponent.vue'), meta: { requiresAuth: false } },
{
path: '/accounttype', component: () => import('../account/AccountType.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/orders', component: () => import('../account/Orders.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/address', component: () => import('../account/Address.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/addAddress', component: () => import('../account/AddAddress.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/loginSecurity', component: () => import('../account/LoginSecurity.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/wishLists', component: () => import('../account/WishLists.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/requestProduct', name: 'RequestProduct', component: () => import('pages/RequestProduct.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/trackYourOrder', name: 'OrderTracker', component: () => import('pages/OrderTracker'), meta: { requiresAuth: false }, props: true
},
{
path: '/sell', name: 'Sell', component: () => import('pages/Sell.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/help', name: 'Help', component: () => import('pages/Help.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/contact', name: 'Contact', component: () => import('pages/Contact.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/vouchers', component: () => import('pages/Vouchers.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/customerCare', component: () => import('../components/CustomerCare.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/dailyGroceries', component: () => import('../components/DailyGroceries.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/stores', component: () => import('../components/Stores.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/searchResult', component: () => import('../pages/SearchResult.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/categories', name: 'Categories', component: () => import('../pages/Categories.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/categories/:categoryName', component: () => import('../pages/CategoriesListPage.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/history', component: () => import('../pages/BrowsingHistory.vue'), meta: { requiresAuth: false }, props: true
},
{
path: '/notifications', name: 'Notifications', component: () => import('pages/Notifications.vue'), meta: { requiresAuth: false }, props: true
}
]
}
]
// Always leave this as last one
if (process.env.MODE !== 'ssr') {
routes.push({
path: '*',
component: () => import('pages/Error404.vue')
})
}
export default routes
Please suggest what is wrong here. Please refer the attached snapshot. As you can see it is showing error for the routes even if routes name are different.
Vue Router Creation Code:
index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
return originalPush.call(this, location).catch(err => err)
}
Vue.use(VueRouter)
export default function (/* { store, ssrContext } */) {
const Router = new VueRouter({
scrollBehavior: () => ({ x: 0, y: 0 }),
routes,
// Leave these as is and change from quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
mode: process.env.VUE_ROUTER_MODE,
// mode: 'history',
base: process.env.VUE_ROUTER_BASE
})
return Router
}
Remove the property name and this message don't show again.
e.g.:
{ path: '/cart', component: () => import('../cart/ShoppingCart.vue'), meta: { requiresAuth: false } }

How to properly use the meta props on vue router?

I'm trying to handle route middleware of the children route, but I got this error
Uncaught TypeError: route.children.some is not a function
The documentation are only shows the example for a single route but in this case, I have a children route that needs to be restricted.
Please take a look at my router configuration:
import Vue from 'vue'
import Router from 'vue-router'
import store from './store/index'
import Home from './views/home/Index.vue'
Vue.use(Router)
let router = new Router({
mode: 'history',
base: process.env.VUE_APP_BASE_URL,
linkActiveClass: 'is-active',
linkExactActiveClass: 'is-exact-active',
routes: [{
path: '/',
name: 'home',
component: Home,
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'login',
// route level code-splitting
// this generates a separate chunk (login.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('./views/auth/Login.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/register',
name: 'register',
component: () => import('./views/auth/Register.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/forgot-password',
name: 'forgot-password',
component: () => import('./views/auth/extras/ForgotPassword.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/database',
name: 'database',
component: () => import('./views/database/Index.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/third-parties',
name: 'third-parties',
component: () => import('./views/third-parties/Index.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/editor',
name: 'editor',
meta: {
requiresAuth: true,
requiresAdmin: true,
requiresEditor: true,
},
children: {
path: ':appSlug/layout-editor/:pageSlug',
name: 'layout-editor',
component: () => import('./views/editor/Index.vue'),
}
},
]
})
router.beforeEach((to, from, next) => {
const isLoggedIn = store.getters['auth/isLoggedIn'];
// Role getters
const isAdmin = (store.getters['auth/isAdmin'] == 'admin') || (store.getters['auth/isAdmin'] == 'super-admin');
const isEditor = store.getters['auth/isEditor'] == 'editor';
// Redirect to the login page if the user is not logged in
// and the route meta record is requires auth
if (to.matched.some(record => record.meta.requiresAuth) && !isLoggedIn) {
next('/login')
}
// Redirect to the homepage page if the user is logged in
// and the route meta record is requires guest
if (to.matched.some(record => record.meta.requiresGuest) && isLoggedIn) {
next('/')
}
// Redirect to the preview page if the user is logged in
// but has no role assigned or the role is user
if (to.matched.some(record => (
record.meta.requiresAuth &&
record.meta.requiresAdmin &&
record.meta.requiresEditor)) && !isAdmin && !isEditor) {
next('/preview')
}
// Pass any access if not match two conditions above
next()
})
export default router
Could somebody please explain it? Why I getting this error and how to fix it?
Thanks in advance.
I just found the answer, kinda silly tho.. I forgot to put square brackets on the children props. Now it's working as I expected.
fix:
{
path: '/editor',
name: 'editor',
meta: {
requiresAuth: true,
requiresAdmin: true,
requiresEditor: true,
},
children: [{
path: ':appSlug/layout-editor/:pageSlug',
name: 'layout-editor',
component: () => import('./views/editor/Index.vue'),
}]
},

Vue-router issue with loading child component

I have an issue.
I have a router like this with child.
{
component: () => import('#/components/roles/Index'),
path: '/roles',
name: 'roles.index',
meta: {
auth: true,
roles: ['admin']
},
children: [{
component: () => import('#/components/roles/Show'),
path: ':id',
name: 'roles.show',
meta: {
auth: true,
roles: ['admin']
}
}]}
When i click on button the url is changing but component is not loading.
<v-btn icon class="mx-0" :to="{ name: 'roles.show', params: { id: props.item.id }}">
<v-icon color="blue">info</v-icon>
</v-btn>
But when i do this like that everything work right
{
component: () => import('#/components/roles/Index'),
path: '/roles',
name: 'roles.index',
meta: {
auth: true,
roles: ['admin']
}
},
{
component: () => import('#/components/roles/Show'),
path: '/roles/:id',
name: 'roles.show',
meta: {
auth: true,
roles: ['admin']
}
}
Logically a path cannot contain param only. path: ':id' will match everything, which is problematic.