Why vue router reloads the component, when this component is the same, but the target route is defined in another children level? - vue-router

Many people have a question: How to reload the component when the route is changed, but the component is the same?.
I have the opposite problem. The component is refreshed, when the "to" route is in different children level then the "from" route.
Vue router 3.0.6.
This is for replacing from route BusinessCaseDetailInsert to route BusinessCaseDetail:
this.$router.replace({ name: 'BusinessCaseDetail', params: { id: newData.BusinessCaseId } });
1) The component is not refreshed, when the "to" and "from" route is in the same level. It is desirable.
var businessCaseDetailRoutes = [
{
path: 'business-case-detail-:id',
name: 'BusinessCaseDetail',
component: () => import('#/components/panels/businesscases/businesscase-detail'),
props: (route) => getBusinessCaseDetailProps(route)
},
{
path: 'business-case-insert',
name: 'BusinessCaseDetailInsert',
component: () => import('#/components/panels/businesscases/businesscase-detail')
}
];
2) The component is refreshed, when the "to" and "from" route is not in the same level. It is not desirable. :-(
var businessCaseDetailRoutes = [
{
path: 'business-case-detail-:idbc',
component: '<router-view></router-view>',
children: [
{
path: '',
name: 'BusinessCaseDetail',
component: () => import('#/components/panels/businesscases/businesscase-detail'),
props: (route) => getBusinessCaseDetailProps(route)
},
{
...
}
]
},
{
path: 'business-case-insert',
name: 'BusinessCaseDetailInsert',
component: () => import('#/components/panels/businesscases/businesscase-detail')
}
];
I need to avoid the refreshing the component, when the target route is defined in different children level.

Related

How to bind query params to named router view

path: '/register',
name: 'Register',
components: {
loginView: () =>
import(/* webpackChunkName: "register" */ '../views/Register.vue'),
},
meta: { guest: true },
// props: { loginView: true },
// how to pass query params to custom router views? this is not working
props: route => ({
email: route.query.email,
token: route.query.token,
}),
How to pass query params to named router view? Using function form as here does not work for named router views. Object form works (commented out one), but that will not map query params to props, only params.
I got answer on discord:
props: {
loginView: route => ({
email: route.query.email,
token: route.query.token
})
}
Basically, if you are using components (object form) instead of component (function form), you need to provide props in same way.
For the completeness I was calling this route: http://localhost:8000/register?token=3424234&email=some#email.com, and loginView is just named router view (<RouterView name="loginView" />).

How to achieve n levels of nested dynamic routes in Vue.js?

I want to achieve n levels of dynamic nested routes in Vue.js, where n is unknown to me.
for eg -
abc.com/ctx-path/component/1/2/...../n
where 1,2,...n are the levels
How can I achieve this with Vue-router?
Behind the scenes vue-router path matching uses path-to-regexp.
So it should be possible to write something like this
{ path: '/ctx-path/component/:id+', component: Component }
or
{ path: '/ctx-path/component/:id*', component: Component }
You could also add path dynamically at run time, but you'll need to have a trigger to add it.
One last option is to have a catch all route and add your own logic.
This is from docs:
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User,
children: [
{
// UserProfile will be rendered inside User's <router-view>
// when /user/:id/profile is matched
path: 'profile',
component: UserProfile
},
{
// UserPosts will be rendered inside User's <router-view>
// when /user/:id/posts is matched
path: 'posts',
component: UserPosts
}
]
}
]
})
see link https://router.vuejs.org/guide/essentials/nested-routes.html
Double dynamic nested routes to filter a single view by the nested URL params
const routes = [
{
path: '/category/:categoryId',
name: 'category',
component: () =>
import(/* webpackChunkName: "product" */ '../views/Categories.vue'),
props: (route: Route) => ({
categoryId: route.params.categoryId,
}),
},
{
path: '/category/:categoryId/:attributeIdsJsonString',
name: 'attributeFilter',
component: () =>
import(/* webpackChunkName: "product" */ '../views/Categories.vue'),
props: (route: Route) => ({
categoryId: route.params.categoryId,
attributeIdsJsonString: route.params.attributeIdsJsonString,
}),
},
];
const router = new VueRouter({
routes,
});
Using different route names like this will mean that beforeRouteUpdate won't fire in some instances, so use beforeRouteEnter as well

How to use vue-router to redirect to 404 page with invalid URL parameter

I use vue-router to navigate the user pages by their user id.
And the router.js looks like as follows
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/user/:id',
name: 'user',
component: () =>
import(/* webpackChunkName: "user" */ './views/User.vue'),
props: true
},
{
path: '/404',
name: '404',
component: () => import('./views/404.vue'),
},
]
})
If someone go to the URL of /user/some-invalid-id, how do I redirect it to the 404 page?
In my app, all user data is loaded at the App.js' breforecreate(), and internally the User view is accessed as follows for existing users
<router-link :to="{name: 'user', params:{id: u.pk}}" >
<a> {{u.first_name}} {{u.last_name}} </a>
</router-link>
I know it's possible to redirect programmatically with a push function call. But I don't know where this code should be used.
this.$router.push('/404')
In the User.vue view page, I use a vuex getter called userByID to retrieve data.
userByID: (state) => id => {
return state.users.find(u => (u.pk == id))
}
Should router.push('/404') happen in userByID or its caller? How do we deal with the template rendering with undefined user object?
I think you want to use 'Navigation Guards`, specifically a beforeEnter hook in your /user/:id route.
Something sort of like this (not tested; just directional):
routes: [
{
path: '/user/:id',
name: 'user',
component: () =>
import(/* webpackChunkName: "user" */ './views/User.vue'),
props: true,
beforeEnter: (to, from, next) => {
if (!userById($route.params.id)) {
next('/404');
}
else {
next();
}
}
}
},
{
path: '/404',
name: '404',
component: () => import('./views/404.vue'),
},
]
Note that you'll need to be able to determine if the user is valid without invoking the User.vue component.
You can also implement a beforeRouteEnter hook on User.vue directly, though you'll not be able to call other User.vue methods there as the component won't yet be mounted.
More on navigation guards: https://router.vuejs.org/guide/advanced/navigation-guards.html#global-guards
Given your userById method is accessing the store, I found this post that might help you access the store in your beforeEnter method: How to access async store data in vue-router for usage in beforeEnter hook?

Vuejs Display a router name in Component

How can I display a router name in a component ?
Example:
const routes = [
{ path: '/documents', component: Documents, name:"Documents" ,props:true},
{ path: '/queries', component: Queries, name:"Queries", props:true}
]
I want to display the name property as a title in the component. Is this possible? how?
props:true will convert path parameters to properties:
{ path: '/documents/:name', component: Documents, name:"Documents", props:true},
You can use an object instead of true and then send in a string.
{ path: '/documents', component: Documents, name:"Documents", props:{ name:'Documents'}},
In your component, register the property
props: { name:String }
And then use it in a template like this:
<div>{{name}}</div>
You can also refer to the route name using the components $route object
<div>{{$route.name}}</div>
To specify title to a component you can use router's meta property, Link
const routes = [
{
path: '/documents',
component: Documents,
name:"Documents" ,
props:true,
meta: {
title: 'Documents'
}
},
{
path: '/queries',
component: Queries,
name:"Queries",
props:true,
meta: {
title: 'Queries'
}
}
]
In main.js,
import router from '#/routes'
router.beforeEach((to, from, next) => {
document.title = `Currently at - ${to.meta.title}`
next()
})

How to Generate Routes for Subcomponents Based on a Base Path

How to get the next route in vue-router
I have the following route: /principal
{path: '/principal', component: Principal}
Now, I need to drive other components that have the same url base,
the new url would be as follows:
/principal/compa
Is it possible to have a single base route be able to display the other components?
Something like this (I know that vue-router does not work like this), but how do you get this behavior?
{
path: '/principal',
component: Principal,
subpath: {
path: 'compa',
component: 'CompA'
}
}
Thanks
There is a children option in VueRouter constructor config to render Vue components with nested routes.
In that particular case, it would be:
{
path: '/principal',
component: Principal,
children: [{
path: 'compa', // it would match /principal/compa
component: CompA
}]
}
From the vue-router doc:
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
children: [ // <-- notice the children property
{
// UserProfile will be rendered inside User's <router-view>
// when /user/:id/profile is matched
path: 'profile',
component: UserProfile
},
{
// UserPosts will be rendered inside User's <router-view>
// when /user/:id/posts is matched
path: 'posts',
component: UserPosts
}
]
}
]
});
Have a look at nested routes for more details.