How to make Nuxt router more dynamic? - vue.js

I am currently replacing a legacy-app with vue.
I have a complex route like /foo/:category/:sub/:match. Most of the time, the urls are just like in that route definition. For some popular url's SEO figured they want short urls like /veryPopularSub.
Is it possible to register an alias for that?
Something like:
{ name: 'generic', path: '/foo/:category/:sub/:match' },
{ path: '/aSpecificShortcut', alias: { name: 'generic', params: { category: 1, sub: 2, match: 3 } } }
When accessing aSpecificShortcut the browser should not redirect

You can use router-extras-module if you want to add more flexibility to your app while staying simple.
Can be used this way
<router>
{
alias: [
'cool-fancy-alias',
]
}
</router>
<template>
...
</template>
Unfortunately, this will not support dynamic path as told here: https://github.com/nuxt-community/router-extras-module/issues/132#issuecomment-725413491
A more in-depth configuration may be tried as explained in my answer here but even tho, I'm not sure that you can have anything dynamic like this
export default {
router: {
extendRoutes(routes, resolve) {
routes.push(
{
name: 'foo-category-sub-match',
path: '/foo/*/*/*',
component: resolve(__dirname, 'pages/data/index.vue'),
alias: 'fancy-path-name' // dynamic here?
}
)
}
}
}
There are some changes on vue-router#4, full list available here: https://next.router.vuejs.org/guide/migration/
Meanwhile, this will not be available in Nuxt until Nuxt3 (powered by Vue3) is released. Still, not sure if it may be supported even there.
There is this github issue, but not sure that this may be extrapolated to alias. Maybe ask it on the project there, #posva is in charge of the Router and doing awesome things there.

Related

How to use a single route in different contexts?

In Nuxt, I have an admin dashboard with a special layout (sidebar), where I use <NuxtChild> to render child routes:
Admin.vue
<NuxtChild :key="$route.path" />
Routes (simplified):
{
path: "/admin",
name: "admin",
component: Admin,
children: [
{
path: '/admin/event/create',
name: 'EventCreate',
component: EventCreate,
props: true
}
// many more routes...
]
}
Now, I want the EventCreate route to also be available alone, in a regular isolated context (NOT in the admin dashboard). This is simple enough with another route. This works fine:
{
path: '/event/create',
name: 'EventCreate',
component: EventCreate,
props: true
}
PROBLEM:
My routes config file will be too messy, with duplicated routes that essentially only differ by path.
Note: I do not use Nuxt's standard file-based routing. Instead all of my route's are defined in one central config file (for many reasons, and my preference). This is done using the Nuxt-Community router library: https://github.com/nuxt-community/router-module. The end result is essentially how Vue-Router works (ie routes defined in a config file).
QUESTION:
Is there a way to define a route once, and have it apply to different contexts (alone or as a child inside another route)?
On a higher level perhaps there's a better way to handle this context switching (plain page vs child-inside-dashboard). In any case, <NuxtChild> works well aside from this, and I wanted to keep using it.
Any suggestions; different idea?
it's easy you can use alias option of vue-router:
{
path: "/admin",
name: "admin",
component: Admin,
children: [
{
path: 'event/create', // not repeat path from root
alias: ['/event/create'],
name: 'EventCreate',
component: EventCreate,
props: true
}
// many more routes...
]
}
and one more note never use a path that starts with / and repeat the parent path in children it doesn't work at all it's verbose, confusing and potentially error-prone
Share route properties with an object
Based on comment by #Estus Flask, here's one way to have a cleaner routes definition:
Use a object to store shared properites, and use it in relevant routes, reducing duplication. Still, you must still have separate routes for contexts, which makes sense.
Object to hold shared properties:
const MyEventCreateRoute = {
component: EventCreate,
props: true,
// other stuff
}
Routes use the shared properties with spread operator:
// Basic route; not in dashboard:
{
path: '/event/create',
name: 'EventCreate',
...MyEventCreateRoute
}
// Route in admin dashboard; renders inside <NuxtChild>:
{
path: "/admin",
name: "admin",
component: Admin,
children: [
{
path: '/admin/event/create',
name: 'AdminEventCreate',
...MyEventCreateRoute
}
]
}

Extend several new paths to a single page in Nuxt

I am struggeling with the nuxt folder/route structure for a project:
I want to achieve:
All of them should show pages/data/index.vue:
www.example.com/data
www.example.com/data/region
www.example.com/data/region/industry
And then access the parameter region or industry via the $route-class.
If I add _region folder and an _industy.vue it will show those files and I want to show and use the index.vue.
EDIT: Since region and industry are probably dynamic.
You could use this setup in your nuxt.config.js file
export default {
router: {
extendRoutes(routes, resolve) {
routes.push(
{
name: 'data-region-industry',
path: '/data/*/*',
component: resolve(__dirname, 'pages/data/index.vue'),
},
{
name: 'data-region',
path: '/data/*',
component: resolve(__dirname, 'pages/data/index.vue'),
},
)
}
}
}
With this configuration, you can go to either /data, /data/:region or /data/:region/:industry with only your index.vue file. No need to make some strange directories or file, you can keep all in one single place.
PS: the order is important. Put the most specific at top, otherwise /data/* will also catch /data/*/* and you'll never reach data-region-industry. This can be double-checked pretty quickly in the router tab of the Vue devtools.
This was taken from the official documentation: https://nuxtjs.org/docs/2.x/features/file-system-routing#extendroutes
I highly recommend giving it a read, especially if you are using Named views.
As for the URL catch, never heard of $route-class but you could make some kind of split on /, pretty doable!
you could use query in the url instead of params.
www.example.com/data
www.example.com/data/?region=x
www.example.com/data/?region=x&?industry=y
you are still able to access the query data via $route.query. if you don't want to use query you have to manually overwrite vue router of nuxt as far as I know.

vue application in php page with router hotlinking

I am currently building a module for a CMS (Joomla) - the frontend of this module is created with VUE 3 incl. Router. The prototype is already working and can be integrated into the CMS Module. Also the router works. If a link is clicked within the VUE app, the corresponding view is displayed. But if the user is now on a subpage of the VUE App and refreshes it (F5 / Ctrl + F5), the page is not found - i think because it exists only in the Vue Router.
To the URL structure:
domain.tld <-- This is where the Vue application is located.
domain.tld/list-:id/item-:id <-- This is the URL for an ITEM
Now I know that it doesn't work like that because the webserver tries to interpret the URL which it can't because parts of it are from VUE.
Is it possible to reconfigure the vue router to work with parameters instead of a "physical" structure?
from: "domain.tld/liste-:id/item-:id"
to: "domain.tld?liste=:id&item=:id"
i think this could solve the issue but i dont know...
Edit:
When i try to use this in the router it still works but has the same effect because yeah "appname" cannot be found by the server..
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/appname?playlist=:id',
name: 'PlaylistDetails',
component: PlaylistDetails,
props: true
},
{
path: '/appname?playlist=:id&video=:vid',
name: 'Player',
component: Player,
props:true
},
]
You can assign a controller to a wild-card, which always return you Vue app:
$router->addMap('/domain.tld/*', 'VueController');
Another approach would be using a # in your URL. Everything after your # will be ignored by the server.
Based on the information i've got from Roman i have changed the routes and added a 404 to the router which refers to home. The views are now been loaded as "url params".
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/#appname?playlist-:id',
name: 'PlaylistDetails',
component: PlaylistDetails,
props: true
},
{
path: '/#appname?playlist-:id&video=:vid',
name: 'Player',
component: Player,
props:true
},
{
// Match all paths vue2 Use * vue3 Use /:pathMatch(.*)* or /:pathMatch(.*) or /:catchAll(.*)
path: "/:pathMatch(.*)*",
name: "404",
component: Home
}
]
If now someone tries to open a site via directlink he got redirected to home.
There might be a better solution but this works when you are using vue inside another PHP app where you are not able to configure the server.
additional info for 404:
https://qdmana.com/2020/12/20201223195804176T.html
It looks that Hotlinks (directly into a view) are not possible in my scenario.

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...

Possible to include an html "partial" template (not embedded in js) in Vue 2 router?

I know I can do this:
const Foo = {
template:
'<div>bar</div>'
}
const routes = [
{ path: '/foo', component: Foo }
]
But I'd rather somehow include an html file like:
const routes = [
{ path: '/foo', component: {template: require('foo.html')} }
]
...WITHOUT using Webpack, Browserfy or anything like that (I'm trying to keep things simple).
The creator Evan You explains here why he didn't want to use templateURLs https://vuejs.org/2015/10/28/why-no-template-url. So, no what you want isn't possible. Now SSR does give some opportunities to structure your app in the way you are talking about. Especially if you are using something like nuxt.js however, this still includes build steps.