Nuxt.js router doesn't seem to load the correct component - vue.js

We are trying out Nuxt.js for an app am having a bit of a problem getting their router to load the correct component. I have structured our directory to generate the following:
path: "/articles/:id?",
component: _241eccb7,
name: "articles-id",
children: [{
path: "edit",
component: _4bdace12,
name: "articles-id-edit"
}]
}, {
The issue is that the articles-id-edit never get invoked. For articles/123, the article-id route is invoked and associated component. For articles/123/edit, the article-id route is invoked and the same component when I'd expect the article-id-edit route to be invoked with its corresponding component.
What am I not understanding? What would be a decent way to debug this (like rake routes in Rails or something). Is there a way I can make more explicit my routes rather than automagically creating?

Is your file structure set up properly? Per the docs:
To define the parent component of a nested route, you need to create a
Vue file with the same name as the directory which contain your
children views.
https://nuxtjs.org/guide/routing#nested-routes

Related

Is there any way to have dynamic routes/components in vuejs router?

Hi beautiful Vuejs developers out there!
I have a little problem with routing many Vue components/pages dynamically. In this scenario I am using nested routes to have a couple of routes for my layout components and hundreds of child routes for my pages and as you can imagine I'll have to type many child routes statically or manually, and then add more when I need more child routes in the future code changes but I need a solution to simplify/solve this problem with more efficient/better way like adding those routes from what user types after the layout in the url... here is my example code code:
const routes: RouteRecordRaw[] = [
{
{
path: '/student',
component: () => import('layouts/StudentLayout.vue'),
children: [
{
path: 'dashboard',
component: () => import('pages/student/Dashboard.vue'),
},
{
path: 'profile',
component: () => import('pages/student/Profile.vue'),
},
],
},
}
As you see in this code I have a layout named Student and it has two children but I'll have to type manually hundreds of child routes for this layout and other layouts is there any way to dynamically set up those routes with what users enter after the layout name like /student/dashboard or /layout/page and match it with a component name? I mean like params in Angular, can I use the param value itself inside the router to say?
{
path: ':pagename',
component: (pagename) => import('pages/student/' + pagename + '.vue'),
},
let me know if there is an efficient way to solve this problem.
Thanks in advance!
I would, personally, not use this, or advise such an approach, nor have I done it, but this idea came to me when I read your question:
My best guess would be to have a handler component which renders a component dynamically based on a route parameter (say you have /:subpage as a child to /student and the handler component is set to that route), and an exception handler around that to show a 404 page when the user types in an inexistent/unsupported route.
For example, I would dynamically import the component by the route parameter into a predefined let (e.g. let SubpageComponent; outside the try catch block), have a try catch block around the dynamic import assignment for the respective error where catch would set the variable to a 404 page. Then I would add the SubpageComponent into the data() of the component doing the rendering of the route.
Edit
I've written out come code that, maybe, makes sense.
It's based on https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components
your routes definition, changed
const routes: RouteRecordRaw[] = [
{
path: '/student',
component: () => import('layouts/StudentLayout.vue'),
children: [
{
path: '/:subpage',
component: () => import('pages/student/SubpageRenderer.vue'),
props: true,
},
],
},
]
SubpageRenderer.vue
<script>
export default {
props: ['subpage'],
data() {
return {
currentSubpage: () => import(`./${subpage}.vue`)
}
}
}
</script>
<template>
<component :is="currentSubpage"></component>
</template>
Instead of using the currentSubpage import, you can also use the subpage route prop to bind :is if subpage is the name of a registered component.
Since this would get only "dashboard" from the route, you'd need some namespacing, like "student-dashboard" with the help of template literals. You could make currentSubpage into a template literal that creates the student-${subpage} name.
I'd probably recommend importing the options object of the component designated by the subpage route parameter instead of registering all the components - if you're registering them, you might as well use vue-router the usual way :)
Also, I only think this could work! It should be tested out, and perhaps casing should be kept in mind, and maybe the Layout suffix as well (subpage will probably be all lowercase, and you'll probably have the components named in PascalCase). After uppercasing the first letter, this could also obviously lead to both /student/Dashboard and /student/dashboard being valid routes

VueJS router alias to particular param

I have a lot of articles in my app, and the URL are written like this in Vue Router: /article/:id.
I have particular articles I want to "pin" and have easier URLs. For example: /pinned-article, which should point to /article/3274 and /other-pinned-article, pointing to /article/68173.
I though about adding this to my routes, but it doesn't work:
{ path: '/article/3274', component: Article, alias: '/pinned-article' }
I thought about something else, involving another component:
{ path: '/pinned-article/:id', component: PinnedArticle }
The component PinnedArticle silently aliasing the correct article with a command like router.alias in the <script> section, but it apparently doesn't exist.
Is there a way to solve this problem? I thought I could use some answers I read here in Stackvoverflow (for examples when it comes to redirect /me to /user/:id, but it doesn't apply.
Thanks in advance :)
addRoute
You can achieve this with Dynamic Routing, which is not the same as dynamic route matching, i.e. route params.
(This solution works in both Vue 3 and Vue 2 with Vue Router >= 3.5.0)
By using the addRoute method of Vue router, you can create routes at runtime. You can either use a redirect or not, depending on whether you want the url bar to read /article/3274 or /pinned.
Redirect
If you want the url to change from /pinned to /article/3274, use redirect:
methods: {
pinRoute() {
this.$router.addRoute({
path: '/pinned',
name: 'pinned',
redirect: { name: 'article', params: { id: 3274 }}
})
}
}
Access the route like:
this.$router.push('/pinned')
The above example assumes you give your Article route a name: 'article' property so you can redirect to it
Alias
You can keep the URL as /pinned using alias. Normally the alias would go on the existing Article route definition, but that doesn't work well with route params. You can use a "reverse alias" with a new route:
methods: {
pinRoute() {
this.$router.addRoute({
path: '/params/3274',
name: 'pinned',
alias: '/pinned',
component: () => import('#/views/Article.vue') // Article component path
})
}
}
Access the route like:
this.$router.push('/pinned')
Notes:
You'll probably want to pass an id argument to the pinRoute methods rather than hardcode them like in the examples above.
A nice thing about addRoute with either method above is if the route already exists, say, from the last time you called the method, it gets overwritten. So you can use the method as many times as you like to keep changing the destination of /pinned. (The docs in both Vue 2 and Vue 3 say the route definition will get overwritten, though Vue 2 router throws a duplicate route warning.)
Of course the pinned route won't automatically persist between app refreshes, so you'll need to save/load the pinned id (i.e. using localStorage, etc.) and run one of these methods on app load if you want that

Data passing using props in router is not working

I am trying to send data from one vue component to another by using props in router. but it is not working. whenever i try to log the props it outputs undefined. code is given below
From where data is sending
Where receiving
in index.js. router setting
None of the code you've posted matches up.
Firstly, the console logging should be just console.log(this.myprops). The point of using props is that you don't need to reference the router itself, e.g. via $router.
Next problem, you're mixing path and params. That isn't allows. See https://router.vuejs.org/guide/essentials/navigation.html. params are for named routes.
I imagine what you're aiming for is something like this:
self.$router.replace({ name: 'DashboardPatient', params: { myprops: authUser.email } })
with router config:
{
path: '/patient',
component: Dash,
children: [
{
path: ':myprops', // <--- Adding myprops to the URL
name: 'DashboardPatient',
component: DashboardPatient,
props: true,
meta: { requiresAuth: true }
}
]
}
Keep in mind that routing is all about building and parsing the URL. So the value of myprops needs to be in the URL somewhere. In my example it comes at the end, so you'll get /patient/user#example.com as the URL. If it weren't in the URL then there'd be no way for the router to populate the prop if the user hit that page directly (or refreshed the page).
To hit the same route using a path instead of a name it'd be something like this:
self.$router.replace({ path: `patient/${encodeURIComponent(authUser.email)}` })
or even just:
self.$router.replace(`patient/${encodeURIComponent(authUser.email)}`)
Personally I'd go with the named route so that the encoding is handled automatically.
If you don't want to put the data in the URL then routing is not the appropriate way to pass it along. You'd need to use an alternative, such as putting it in the Vuex store.

Vue router not navigating

I'm having problems getting VueRouter to navigate.
Within my app some pages work fine, and with identical code, other pages the routing doesn't work / page doesn't update navigate.
Are there some gotchas with the router? Like you cannot call the router from within components or... ?
named route in my app
export default new VueRouter({
routes: [
{
path: '/grams/one/:cname',
component: GramsOne,
name: "gramsOne"
},
...
Then inside a component on a page:
<q-btn v-for='(rel, key) in gram.relatedItems' :key='key'
color='secondary'
#click="goGram(rel)"
>
{{rel.cn}}
</q-btn>
// later in the script:
methods: {
goGram(gram) {
let newRoute = {
name: 'gramsOne',
params: {cname: gram.cname}
}
console.log('goGram', newRoute)
this.$router.push(newRoute)
}
},
Elsewhere on the same page, simple routes work.
The URL address will get updated in the browser.
I see the right console log with route info
But the page/content will not change.
Once the URL bar has been updated, I can hit ctrl-R and the new page will get loaded. So the destination route is working fine.
From other pages in the same app I can use the same route to target new destination and loads fine.
This is also loading with the same URL and just a query param different that is causing the problem.
/app/items/foo
/app/items/bar
where bar is a type of some property /app/items/:foo
I have tried various combinations of named routes, routes using etc, and can't really see a pattern.
"vue": "~2.5.0",
"vue-resource": "^1.3.4",
"vue-router": "^2.7.0"
Thanks any hints!
The Component in this case is the same, so vue will reuse the instance.
The this.$route in the component will change but created(), beforeMounted() and mounted() hooks won't be callled.
Which is probably where you use the this.$route.params.cname
To force vue to create a new component instance you can set a unique key on the like <router-view :key="$route.fullPath">
Another options is to react to changes in the $route with a watcher:
watch: {
"$route.params.cname": {
handler(cname) {
// do stuff
},
immediate: true
}
}
Router can be called within a component just fine. In fact, you usually call router from the component.
From the code snippets provided, at one point in the code you use cn, then at other point you use cname. That might be the problem why it never quite work for you.
I create a codesandbox to recreate your scenario, and besides that minor naming mentioned above, things seem to work just fine.

Dynamically add child routes in Vuejs

According to this official example, we have the ability to add nested/children routes in vuejs. But I cannot find any help/docs around a way to add these children routes dynamically. e.g only add child routes when Parent route is visited.
Currently all the routes in a Vue application are defined in a single place where we create Router instance. There is an api called addRoutes, but I don't know how to use that to add lazily loaded features of application along side their routes. If someone is familiar with Angular2+ Module system, that has this ability to define routes for the feature modules inside that module and even make them lazily loaded. Wondering if something could be achieved with VueJs?
You can use $router.addRoutes to re-add a route, specifying children.
You'll need to get the current route definition (as opposed to the $route object) by searching the $router.options.routes array for the route definition object that matches the current $route.path. Then add a children array of route definitions to the object and pass it to $router.addRoutes.
created() {
let { routes } = this.$router.options;
let routeData = routes.find(r => r.path === this.$route.path);
routeData.children = [
{ path: 'bar', component: Bar },
{ path: 'baz', component: Baz },
];
this.$router.addRoutes([routeData])
}
Here's an example fiddle of dynamically adding child routes in the created hook of a route's component definition.