Optional route params with Vue Router - vue.js

In my Vue 2.7.5 app (using Vue Router 3.5.4) I'm trying to define this route
{
path: '/messages/:messageId?/replies/:replyId?',
name: 'messages',
component: () => import('#/views/messages')
}
The intent is
to see all messages use /messages
to see a specific message use /messages/:messageId
To see a specific message and a specific reply to that message use /messages/:messageId/replies/:replyId
However, if I navigate to this route without specifying any route params using
<router-link :to="{name: 'messages'}">
Then the URL is resolved as /messages/replies, but I would like it to be resolved as /messages.
Essentially, what I want is: don't include /replies unless there's a replyId param, but I don't know how to express that.
One solution is to use the following instead:
<router-link :to="{ path: '/messages'}">
But I prefer to always refer to routes by name, because this gives me the flexibility to change the paths without breaking anything

The easiest solution for you is to remove /replies and only have path like this:
'/messages/:messageId?/:replyId?'
(Optional solution)
If removing that part of url is not an option and using named routes is a must, here is an alternative solution where you use two named routes. If the replyId is missing you can redirect before enter to the 2nd named route.
{
path: '/messages/:messageId?/replies/:replyId?',
name: 'message-replies',
component: () => import('#/views/messages'),
beforeEnter({ params }) {
if (!params.replyId) {
return {
name: 'messages',
params: {
messageId: params.messageId,
},
};
}
},
},
{
path: '/messages/:messageId?',
name: 'messages',
component: () => import('#/views/messages'),
},

Related

Vue3: How to send params to a route without adding them to the url in Vue3?

In Vue3 is there a way to pass properties to a route without the values showing in the url?
I defined the route like this:
{
path: '/someRoute',
name: 'someRoute',
component: () => import('#/app/pages/SomeRoute.vue'),
props: (route) => {
...route.params
}, // <-- I've seen this method in Vue2 but in Vue3 the route.params is just empty here
}
I call the route like this:
<router-link :to="{ name: 'someRoute', params: { message: 'Some Message' } }">Some link</router-link>
When I change path into path: '/someRoute/:message', the message come through just fine but I just want to pass the message without it showing up in the url.
I've seen a couple of Vue2 examples that use this method (e.g. https://stackoverflow.com/a/50507329/1572330) but apparently they don't work in Vue3 anymore.
Also all the examples in the Vue3 docs (https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js / https://v3.router.vuejs.org/guide/essentials/passing-props.html) pass on their values through the url itself so I'm not sure if it's even possible anymore.
Any thoughts on this would be helpfull.
Finally I found something about this in the changelog: https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22
Apparently it's no longer possible to send properties via params without the showing in the url. But fortunately they give some alternative suggestions.
The one that worked best for my situation was to use state: { ... } instead:
<router-link :to="{ name: 'someRoute', force: true, state: { message: 'Some Message' } }">Some link</router-link>
Now in the code of the page I read the property from the history.sate and put the value in whatever property I need it.
In case the url/route itself doesn't change you need to have an update hook and use force: true
public created() {
this.message = window.history.state.message;
}
public updated() {
this.message = window.history.state.message;
}
PS history.state has some limitations so in other situations one of the other suggestions from the changelog might work better

How to change base url in VUE router?

Current URL is 'https://localhost:3000/lang/countries/states/cities/'
I want to change it to:
https://localhost:3000/lang/compare/?c=1&back=1&query=94&query=911
Basically I want to edit the current URL. I tried using:
this.$router.push({
path:'/lang/compare/?c=1&back=1&query=94&query=911',
});
this.$router.replace({
path:'/lang/compare/?c=1&back=1&query=94&query=911',
});
But this changes the URL to :
https://localhost:3000/lang/countries/states/cities/lang/compare/?c=1&back=1&query=94&query=911',
I have tried using window location href but coz of that state of my variable is lost, hence I need to use VUE router for this. Is their any way to change base URL in VUE routes.
Your method is also right it should work if there is no other issue,
try with
this.$router.push({ path: '/lang/compare', query: { c: 1,back:1,firstquery:94,queryB:991}})
or you can also try with $router name defining a name on router index file
{
path: "/lang/compare",
name: "compare",
component: comparePage,
},
this.$router.push({ name: 'compare', query: { c: 1,back:1,firstquery:94,queryB:991}})

Vuejs show product page in combination with repeatable route params as nested categories

I would like to access a product details page within the set of categories.
For example: website.com/catalog/cat1/cat2/cat3/product-item-123
I'm using a Repeatable params to construct a nested set of categories, so URL would look like this which works fine:
website.com/catalog/category/subcategory/anothersubcateg/
{
path: '/catalog/:slug+',
name: 'category.show',
component: () => import('pages/category.show.vue'),
props: route => ({ slug: route.params.slug })
},
But when I add a new route rule it overrides all pages for categories and shows a product page instead:
{
path: '/catalog/:slug+/:productSlug',
name: 'product.show',
component: () => import('pages/product.show.vue'),
props: route => ({ slug: route.params.slug })
}
How to render a pages/product.show.vue file only when the product page is opened and not override the pages/category.show.vue file ?
UPDATED
Here is the list of URLs I would like to have:
format: /CAT+/PRODUCT_ID-PRODUCT_SLUG
/clothes/t-shirts/winter/men/20380-underarmor-crossfit-99x
/hardware/gpus/87689-nvidia-rtx-3080ti-24gb
/smartphones/ios/iphone-13-pro-512gb
As you cannot use regex to help you sort products from categories, the simplest solution seems to be to add a separator section to your url to tell the router that what follows is a product:
path: '/catalog/:slug+/product/:productSlug',
Tell me if you're still facing an issue. Happy coding!

Vue router not matching route with more than one slash

basically my issue is that I want to pass a router prop called name into an article route, so something like /article/:name. When I direct to that route internally, like with $router.push(name: 'article', params: {name: 'something'}), it works just fine. But when I then use that url, /article/something, the route doesn't match and the page is blank.
But if I just use /:name instead of /article/:name, everything works just fine. Does anyone have any idea why the /article part could be causing the route to fail to match? Thanks in advance.
EDIT: Route definition:
{
path: '/article/:name',
name: 'article',
component: () => import('../views/Article.vue'),
props: true,
}
When I navigate to /article/something, the page is blank, no matter what something is. But if I have the following route definition:
{
path: '/:name',
name: 'article',
component: () => import('../views/Article.vue'),
props: true,
}
and navigate to /something, it works just fine.

How to redirect non-dynamic urls with vue-router

We have a vue.js app for an insurance company where every agent has their own dynamically-generated website. Currently, if you visit a gibberish link, it will show the blank agent template. We need urls that don't include an agent's slug to redirect to our "NotFound" component.
Below is our vue-router code if there happens to be an easy fix. Otherwise is it easier to add a computed function to redirect a visitor if, for example, the agent.name == null?
Thanks for any help!
Example of a good url: https://my.piaselect.com/georgebeach
Example of a bad url: https://my.piaselect.com/georgebeach2
Our router:
{
path: "/:id",
component: AgentSite,
name: 'AgentSite',
props: true
},
{
path: '*',
name: 'NotFound',
component: NotFound
}
Building on what #Jacob Goh has said.
You need a way to to now if the agent id is valid or not. Let's assume you have a list of agent id's, you can use a route guard to block the route to invalid ids.
https://router.vuejs.org/en/advanced/navigation-guards.html
I haven't tested this, but you should be able to get the general idea.
const agentIds = ['Bob', 'Michael']
const router = new VueRouter({
routes: [
{
path: '/foo:id',
component: Foo,
beforeEnter: (to, from, next) => {
if (agentIds.includes(to.params.id)) {
// The agent is fine - continue
next();
} else {
// doesn't exist - go back to root or any other page
next({ path: '/' });
}
}
}
]
})
it doesn't work because you don't specify any name in this path :
{
path: "/:id",
component: AgentSite,
name: 'AgentSite',
props: true
},
because of that, this path allow any random chars at the root to return the component AgentSite (but blank because the random chars "param" fit to nothing in the component i guess).
To prevent that, you can specify a name to your path : path: "agent/:id" for example.
Edit : it seems you already had a great solution here...