Vue-Router - Dynamic Nested Routes

Independence for your routes!

By Janis
January 4, 2021
Vue-Router - Dynamic Nested Routes

Why would you use Vue-Router in your Vue project?

Vue-Router provides you with a great way to define and organize your frontend routes, which is mainly helpful if you are about to create a Single Page Application (SPA).

Yet, Caleb Porzio tweeted about registering Vue-Router inside a Single File Component (Tweet: which was an eye-opener for me! Think about it! You can build Components and define the component-specific routes inside them, what also makes them nestable if you have child components (with a bit more work, but more about that later).

Defining all routes inside your app’s entry point was stopping me from using Vue-Router at all. Why? Imagine you have 50 routes and it’s components to define in one single file. This will just get hard to maintain quickly. However, with our gained knowledge of component driven routes we can store the routes isolated in our components, and we can even reuse them, so we keep our app dry, I’m hooked!

I started to play around with this approach, but shortly found that nesting those router components did not work as expected. If you just create multiple Vue-Router instances, the URL matching does not work like it is supposed to. Child components do not know the path of its parent component, so there is a bit more to do than just creating a Vue-Router instance in every child component.

Let’s say we want to have two main links on our page and a vertical menu inside the content of the first link. This way we have two nested routers, but to make it more clear, we also add a section with tabs inside the nested route.

Here is our working example:

So, how does it work?

First, we need to create the main instance of our router. We also need to create two new routes for our main pages. The first one is called “/nested” and the second one is called “/single”. There is nothing special about the single one, but for the nested route, we need to set the alias value to “/nested/*” in order to match all nested routes.

Why do we want this? It’s quite simple. If we visit the URL “/nested/tabs” we want to resolve the “Tabs” component through the “VerticalMenu” component since the “Tabs” component is registered within the “VerticalMenu” component.

We also need to pass the “basePath” as a metadata into the route component. So our routes' config should look like this:

The VerticalMenu component

Now the fun part begins. Inside the VerticalMenu component, we need to do things differently than in the main component. In order to register routes inside components with awareness of the parent routes, we need to do 4 things:

  1. Create a new Vue-Router instance without defining any routes.

  2. Make sure that the routes we want to register are not already registered.

  3. Add routes dynamically within Vue’s created hook. (We need to do this, so we can access the current component, which gives us access to the $parent inside the routeHelper.js. This is needed in order to fetch the basePath from the metadata, which we defined earlier.)

  4. Always use route names to reference a route, since our paths are dynamic.

The getParentRouterPath(this) function returns our parent route so we can nest our URLs infinitely. However, it will return an empty string if there is no parent route which gives us the possibility of registering this component anywhere without the need of having a parent router instance.

The routeNameAlreadyRegistered(router, routeName) function will only check if the routes are not present already, so Vue-Router does not throw the “route already exist” warning if the component gets reloaded.

That’s it!

Let me know if you have any questions or suggestions about this approach. If you want to get in contact, feel free to hit me on Twitter.