I've been searching for index routes in the vue-router docs, but couldn't find how to do this:
I have
const routes = [
{ path: '/:slug', component: Project }
];
What I want is to specify a hardcoded slug for "/" (root), and to use the Project component for this path as well. Something like (this is wrong):
const routes = [
{ path: '/', {'slug':'home-project'}, component:Project})
{ path: '/:slug', component: Project }
];
many thanks!
Okay, that was easy
const routes = [
{ path: '/', component: Project }
{ path: '/:slug', component: Project }
];
then in Project:
let slug = this.$route.params.slug;
if (!slug) {
slug = 'some-default-slug';
}
Related
In my Vue 2.7.5 app (using Vue Router 3.5.4). I'm trying to map multiple URLs to the same component. Currently, I have a single route mapped to the component:
{
path: '/customer/:customerId',
component: CustomerOrders
}
My goal is to add an optional orderId parameter, such that if a URL like /customer/42/order/59 is accessed, then the same component is loaded, but the order with ID 59 is highlighted (the details of how the param is going to highlight the order are not important).
I tried changing the path to /customer/:customerId/orders/:orderId?, but this would no longer match any URLs of the form /customer/:customerId and would therefore be a breaking change.
My current solution is to use a child route:
{
path: '/customer/:customerId',
component: CustomerOrders,
children: [
{
path: 'order/:orderId',
component: CustomerOrders
}
]
}
This work as the CustomerOrders component is loaded by paths matching either /customer/:customerId or /customer/:customerId/order/:orderId, but it seems like a slightly convoluted approach and I'm not sure it's an appropriate use of child routes.
Is there a better solution?
The easiest way is to register the same component for both routes:
{
path: '/customer/:customerId',
name: 'CustomerOrders',
component: () => import( '../views/CustomerOrders.vue'),
},
{
path: '/customer/:customerId/order/:orderId',
name: 'CustomerOrders',
component: () => import( '../views/CustomerOrders.vue'),
},
An exact solution that you are looking for is parsing params manually:
{
path: '/customer/:param+',
name: 'CustomerOrders',
component: () => import( '../views/CustomerOrders.vue'),
props: router => {
const params = router.params;
const split = params.param.split('/');
params.customerId = split[0];
if (split.length > 2) {
params.orderId = split[2];
}
},
},
Here the :params+ ensures that a customerId and the rest of the route get caught. On the other hand, using :params* catches the /customer route without even a customerId.
CAUTION This approach also /customers/42/...everything...
The vue3 solution is solved here.
EDIT: the following approach cannot catch orderId
Using an alias improves reusability and reduces rendering time but comes with a price of capturing params-change in a watch handler.
{
path: '/customer/:customerId',
name: 'CustomerOrders',
alias: '/customer/:customerId/order/:orderId',
component: () => import( '../views/CustomerOrders.vue'),
},
In this case, your component doesn't get rebuilt by changing routes and also onMount or beforeCreate hooks don't get called either. To catch params-change add a proper watch:
export default {
name: 'CustomerOrders',
watch: {
'$route.params'() {
console.log('params changed. Extract params manually and reload');
},
},
};
This issue is addressed here.
Hi i'm facing a problem where i want to add new route dynamically
My route structure will look something like this
I'm using "vue-router": "^3.5.3"
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, name:'User'
children: [
{
path: 'profile', component: Profile, name:'Profile'
children: [
{
path: 'about', component: About, name:'About'
children: [
{
path: 'details', component: Details, name: 'Details'
}
]
}
]
}
]
}
]
})
Now my intention is to add child route to Details
this is how my pseudo code looks like
findRouteWithName(routeObj,routeName)
{
// recursive find with any nested level
....
return foundRoute;
}
let routeObj = findRouteWithName(this.$router.options.routes,'Details');
routeObj.children.push(Route object{});
//this.$router.addRoutes([routeObj]) // this line creates problem as mentioned below in **problem:**
Note: if i'm doing like this https://stackoverflow.com/a/48833074/10054910 it is creating multiple nested routes in the url
Problem: page is becoming blank with direct push on children even route does not change in url. with this https://stackoverflow.com/a/48833074/10054910 approach route changes in url but append 2 times
Please help me thanks in advance !!
I'm using Vue Router with Vue 3 and am trying to add a catch-all route to redirect the user if they try and access an invalid URL. When I try and use the wildcard (*), i get the following error logged to the console:
Uncaught Error: A non-empty path must start with "/"
at tokenizePath (vue-router.esm.js?8c4f:975)
at createRouteRecordMatcher (vue-router.esm.js?8c4f:1106)
at addRoute (vue-router.esm.js?8c4f:1190)
at eval (vue-router.esm.js?8c4f:1335)
at Array.forEach (<anonymous>)
at createRouterMatcher (vue-router.esm.js?8c4f:1335)
at createRouter (vue-router.esm.js?8c4f:2064)
at eval (index.js?a18c:26)
at Module../src/router/index.js (app.js:1402)
at __webpack_require__ (app.js:854)
I'm assuming this is because I don't prepend the path containing the asterisk with a '/', but if I do this then the catch all doesn't work. Here are my routes:
imports...
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/user',
name: 'User',
// route level code-splitting
// this generates a separate chunk (user.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "user" */ '../views/user/User.vue'),
children: [{path: '', component: UserStart}, {path: ':id', component: UserDetail}, {path: ':id/edit', component: UserEdit, name: 'userEdit'}]
},
{path: '/redirect-me', redirect: '/user'},
{path: '*', redirect: '/'}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
The wildcard route is the last object in the routes array. Does anyone know what I'm doing wrong?
Catch all routes (/*) must now be defined using a parameter with a custom regex: /:catchAll(.*)
For example:
{
// path: "*",
path: "/:catchAll(.*)",
name: "NotFound",
component: PageNotFound,
meta: {
requiresAuth: false
}
}
Personally, for Vue 2's * (star or catch all) routes in Vue 3 I use:
{
path: '/:pathMatch(.*)*', <== THIS
name: 'not-found',
component: NotFound
}
Catch all routes (*, /*) must now be defined using a parameter with a custom regex:
The parameter name can be whatever you want like catchAll, pathMatch, noPage etc
{
path: '/:pathMatch(.*)*', //will match everything and put it under `$route.params.pathMatch`
name: 'not-found',
component: NotFound
}
{
path: '/user-:afterUser(.*)',// will match anything starting with `/user-` and put it under `$route.params.afterUser`
component: UserGeneric
}
/:pathMatch(.*)*
The last * it is necessary if you plan on directly navigating to the not-found route using its name.
If you omit it the / character in params, it will be encoded when resolving or pushing.
For example if you use path: /:pathMatch(.*) (note: without the last asterisk) and you go to /user/not-found (a page that doesn't exists) the this.$route.params.pathMatch will be a string => 'user/not-found'
// bad example if using named routes:
router.resolve({
name: 'bad-not-found',
params: { pathMatch: 'not/found' },
}).href // '/not%2Ffound'
Instead, if you use path: /:pathMatch(.*)* (note: with asterisk) this.$route.params.pathMatch will be an array ['user', 'not-found']
// good example:
router.resolve({
name: 'not-found',
params: { pathMatch: ['not', 'found'] },
}).href // '/not/found'
Please read docs: From migration from vue 2 to vue 3 and Catch all / 404 Not found Route
in a nuxt.js app, I have nested routes like this:
route-1/route-2/route-3
I want to add an optional param after route-1 to render the same old route but with extra info(item id or something like that), which mean it will map to 2 route formats
route-1/:param/route-2/route-3 or route-1/route-2/route-3
without duplicate my folder structure
if I add a file with the param name it will be a required param and I will have to duplicate the folder structure without this param to handle the 2 scenarios
In my case solved with this. I have this pages tree:
pages/
--| search/
----| index.vue
--| index.vue
I need an optional 'category' param in the search page. I will to extend the routes like this:
// nuxt.config.js
export default {
router: {
middleware: [...],
extendRoutes (routes, resolve) {
routes.push({
name: 'search-category',
path: '/search/:category',
component: resolve(__dirname, 'pages/search/index.vue'),
chunkName: 'pages/search/_category/index'
})
}
}
}
If I navigate to /search or /search/my-category this render the same page in both cases, and in the second case I have the value my-category in $route.params.category :)
In your case, perhaps something like:
// nuxt.config.js
export default {
router: {
middleware: [...],
extendRoutes (routes, resolve) {
routes.push({
name: 'my-new-route',
path: '/route-1/:param/route-2/route-3',
component: resolve(__dirname, 'pages/same-route/index.vue'),
chunkName: 'pages/same-route/_param/index'
})
}
}
}
BTW: chunkName is necessary if you use nuxtI18n plugin, and after, in this plugin, the configuration for the dynamic route is (in my case):
// nuxt.config.js
export default {
i18n: {
pages: {
'search/index': { // <-- route in pages tree
es: '/buscar',
en: '/search'
},
'search/_category/index': { // <-- dynamic route configured
es: '/buscar/:category',
en: '/search/:category'
}
}
}
}
I have the following structure in vue.js ,using vue-router.
routes: [
{
path: '/domains',
component: ListOfDomains
},
{
path: '/domain/:domainName',
component: Domain,
children: [{
// Photos Tab content will be rendered inside domain's <router-view>
// when /domain/:id/photos is matched
path: 'posts',
name: 'posts',
component: PostsTabContent
},
{
path: 'photos',
name: 'photos',
component:PhotosTabContent
}
]
}
]
In my Domain component I use a watcher to fetch domain related data from server such as:
"$route": function(to, from) {
console.log("watcher triggered");
//do update only if domain has changed
//do something , ajax request , update store etc
}
This seems to work fine, but my problem is that I only want to do my updates if the url changes from, say, domain/domain23/posts to domain/domain45/posts and not when it changes from domain/domain23/posts to domain/domain23/photos.
How can I watch only that level in the route for changes?