Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nested routes without parent component #2105

Closed
rightaway opened this issue Mar 14, 2018 · 23 comments
Closed

Allow nested routes without parent component #2105

rightaway opened this issue Mar 14, 2018 · 23 comments

Comments

@rightaway
Copy link

What problem does this feature solve?

Allows the routes to be defined with a prefix that doesn't need to be repeated in each route.

What does the proposed API look like?

Currently this doesn't work because the parent route doesn't have a component specified. This feature isn't about nested routes but just about nested paths.

{ path: '/prefix': children: [
  { path: 'one', component: ... },
  { path: 'two', component: ... },
]}

Creates /prefix/one and /prefix/two.

@posva
Copy link
Member

posva commented Mar 14, 2018

If you need nested path the recommended approach is to use a function to generate the routes with the prefix:

function prefixRoutes(prefix, routes) {
	return routes.map(route => route.path = prefix + '/' + route.path)
}

new Router({
	routes: [
		// some routes
		...prefixRoutes('/prefix', [
		  { path: 'one', component: ... },
		  { path: 'two', component: ... },
		])
	]
})

@posva posva closed this as completed Mar 14, 2018
@deckar01
Copy link

deckar01 commented Aug 23, 2019

I hacked around this with a component named PassThrough that just contains a <router-view />. It should be possible to make this the default behavior when the component property is omitted from a route.

<!-- PassThrough.vue -->
<template>
  <router-view />
</template>
// router.js
new Router({routes: [{
  path: '/prefix',
  component: PassThrough,
  children: [
    { path: 'one', component: ... },
    { path: 'two', component: ... },
  ]
}]})

@vipulw2011
Copy link

If you need nested path the recommended approach is to use a function to generate the routes with the prefix:

function prefixRoutes(prefix, routes) {
	return routes.map(route => route.path = prefix + '/' + route.path)
}

new Router({
	routes: [
		// some routes
		...prefixRoutes('/prefix', [
		  { path: 'one', component: ... },
		  { path: 'two', component: ... },
		])
	]
})

How should specify path to direct? Just specifying without prefix or with both is taking me to 404.

@GastonDonnet
Copy link

GastonDonnet commented Apr 29, 2020

If you need nested path the recommended approach is to use a function to generate the routes with the prefix:

function prefixRoutes(prefix, routes) {
	return routes.map(route => route.path = prefix + '/' + route.path)
}

new Router({
	routes: [
		// some routes
		...prefixRoutes('/prefix', [
		  { path: 'one', component: ... },
		  { path: 'two', component: ... },
		])
	]
})

This throw a error because inside the map you return only the path.
The solution is:

function prefixRoutes(prefix, routes) {
  return routes.map((route) => {
    route.path = prefix + '' + route.path;
    return route;
  });
}

Example:

...prefixRoutes('/shop/:shopId', [
        {
          path: '/',
          name: 'Shop',
          component: () => import('../views/shop/Shop.vue'),
        },
        {
          path: '/category/:categoryId',
          name: 'Shop Products',
          component: () => import('../views/shop/Shop.vue'),
        },
      ]),

Routes return:

4: {path: "/shop/:shopId/", name: "Shop", component: ƒ}
5: {path: "/shop/:shopId/category/:categoryId", name: "Shop Products", component: ƒ}

You can change the union with prefix inside the function ("") to ("/") if you not start the children paths with "/"

@andreasvirkus
Copy link

Expanding on what @deckar01 proposed, we can do away with the redundant SFC 👇

new Router({routes: [{
  path: '/prefix',
  component: {
    // Inline declaration of a component that renders our <router-view>
    render: (c) => c('router-view'),
  },
  children: [
    { path: 'one', component: ... },
    { path: 'two', component: ... },
  ]
}]})

@oles
Copy link

oles commented Nov 21, 2020

Just hit this issue again. I keep on forgetting this one on new projects where it makes sense to "namespace" several pages... and then I wonder why things broke, as there's just a blank page without error messages.

Then I re-read the docs, and read the thing with two <router-view></router-view> in https://router.vuejs.org/guide/essentials/nested-routes.html, and search for like "vue nested routes without main component", find this issue, and remember that I have to use the solution above.

It makes little sense to me that the child is not inserted into the main <router-view></router-view> when the parent has no component.

Also - hello, future me 👋

@asebold
Copy link

asebold commented Dec 2, 2020

I'd also like to give this issue a "bump".

Nested routes are particularly helpful for displaying a breadcrumb in my UI. Though the routes are nested, there's no point nesting components.

For example, in my app the path /leagues/:leagueId should render a completely different page than /leagues/:leagueId/teams/:teamId. At most, these pages share a top level component that serves as a base template. But the :teamId page should not inherit anything from the :leagueId page. They show completely different information and operate independently of each other. Currently I use the "pass through" option explained above, but creating a "dummy" component just to get the app to render correctly feels hacky.

It would be cleaner and less cumbersome if we didn't have to add a component to every route, and a child route was rendered in the component of it's closest ancestor with router-view.

@carmel
Copy link

carmel commented Dec 6, 2020

Expanding on what @deckar01 proposed, we can do away with the redundant SFC 👇

new Router({routes: [{
  path: '/prefix',
  component: {
    // Inline declaration of a component that renders our <router-view>
    render: (c) => c('router-view'),
  },
  children: [
    { path: 'one', component: ... },
    { path: 'two', component: ... },
  ]
}]})

hi, @andreasvirkus. Do you know how to use it in next router of vue 3 ?
it will be throw TypeError with render: (c) => c('router-view')
image

log the 'c' out as follow:
image

@andreasvirkus
Copy link

andreasvirkus commented Dec 7, 2020

I think you'd need to use Vue.h (docs: https://v3.vuejs.org/guide/render-function.html#render-functions)

import { h } from 'vue'
// or 
// import Vue from 'vue' // and use it as `Vue.h`

// router setup...
  render: () => h('router-view'),

I haven't tested this through yet though.

@carmel
Copy link

carmel commented Dec 16, 2020

@andreasvirkus Thank you, It's all right!

@Jenesius
Copy link

Jenesius commented Jan 17, 2021

@carmel
Hello dear team!
Also u can use RouterView constructor to make ur code clean!

import {RouterView} from "vue-router";
export default [
    {
        path: "/import-permits",
        component: RouterView,
        children: [
            {
                path: "applications",
                component: RouterView,
                children: [
                    {
                        path: "list",
                        name: "list",
                        component: ViewIPApplicationsList
                    }
                ]
            }
        ]
    }
]

@james-becker
Copy link

james-becker commented Mar 1, 2021

@Jenesius While the above looks promising, I could not get it to work.

@Jenesius
Copy link

Jenesius commented Mar 1, 2021

@Jenesius While the above looks promising, I could not get it to work.

What version of VUE u use?

@azollai
Copy link

azollai commented May 7, 2021

I use vue-router 3.5.1 and I also don't have option to import RouterView.
Would be nice, though..
image

@Jenesius
Copy link

Jenesius commented May 7, 2021

@azollai
VueRouter is available for vue-router 4.x. version (from vue-router-next / Vue3 )

@dnikl
Copy link

dnikl commented Aug 11, 2021

Is there a way to pass through multiple named router-views from a parent component to its children? In the example, there are children with and without a sideBar.

MicrosoftTeams-image (1)

MicrosoftTeams-image

@marsimeau
Copy link

We have been using component: RouterView, but now <transition> doesn't trigger between children routes. We are computing a key to get around that issue. However, this solution requires route related logic to be written in our Layout which isn't ideal.

@Soren-Knudsen
Copy link

@dnikl: Did you ever find a solution for this? I have precisely the same use case

@dnikl
Copy link

dnikl commented Jan 26, 2022

@Soren-Knudsen unfortunately not.

@lifenautjoe
Copy link

4 years later, I keep coming back to this issue...

@anaselbahrawy
Copy link

anaselbahrawy commented Feb 14, 2022

nested routes and nested names and meta group

function prefixRoutes(prefix, name, meta, routes) {
    return routes.map((route) => {

        route.path = '/' + prefix + '' + route.path;

        let named = name + '.' + route.name

        route.name = named.replace(/\.$/, "")

        Object.assign(route.meta, ...meta)
        
        return route;
    });
}

you can call function like ...prefixRoutes('admin', 'admin', [{AdminAuth: true}], []),

@Mouvedia
Copy link

Mouvedia commented Jul 5, 2022

Anyone found a clean solution to get rid of this warning :

[Vue Router warn]: <router-view> can no longer be used directly inside <transition> or <keep-alive>.

when using component: RouterView,?

@Pinnokkio
Copy link

Any news on this about how to add nested routes without parent component?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.