25

I have an issue with a default child route in Vue.js 2.

When I visit localhost/listings initially, it correctly loads index.vue and map.vue as a child.

When I navigate using router-link to localhost/listings/1, and then using router-link back to localhost/listings, then it still loads the show.vue template. This shouldn't happen?

I have no navigation guards or anything that should interfere. Is there anyway to correct this?

My routes:

window.router = new VueRouter({
  routes: [
    ...

    {
      path: '/listings',
      name: 'listing.index',
      component: require('./components/listing/index.vue'),
      children: [
        {
          path: '',
          component: require('./components/listing/map.vue')
        },
        {
          path: ':id',
          name: 'listing.show',
          component: require('./components/listing/show.vue')
        }
      ]
    },
    
    ...
  ]
});

4 Answers 4

38

The "father" router should not be named if you want a default child route, so instead using :to="{name: 'listing.index'}", use the name of the default child route (e.g :to="{name: 'listing.map'}").

The code should look like this:

window.router = new VueRouter({
routes: [

    ...

    {
        path: '/listings',
        component: require('./components/listing/index.vue'),
        children: [
            {
                path: '',
                name: 'listing.map'
                component: require('./components/listing/map.vue')
            },
            {
                path: ':id',
                name: 'listing.show',
                component: require('./components/listing/show.vue')
            }
        ]
    },

    ...

  ]
});
Sign up to request clarification or add additional context in comments.

Comments

30

Maybe try re-arranging the children, routes are fired in the order they match from top-to-bottom, so this should hopefully fix it:

window.router = new VueRouter({
    routes: [

    ...

    {
        path: '/listings',
        name: 'listing.index',
        component: require('./components/listing/index.vue'),
        children: [
            {
                path: ':id',
                name: 'listing.show',
                component: require('./components/listing/show.vue')
            }
            {
                path: '',
                component: require('./components/listing/map.vue')
            },
        ]
    },

    ...

  ]
});

Just for a bit of clarification, your path: '' essentially serves as a "catch all", which is likely why when it's at the top it's being found immediately and so the router never propagates any further down to the :id route.

2 Comments

Vue now warns this pattern: Named Route 'upload' has a default child route. When navigating to this named route (:to="{name: 'upload'"), the default child route will not be rendered. Remove the name from this route and use the name of the default child route for named links instead.
According to this github.com/vuejs/vue-router/issues/777#issuecomment-253786416, you need to remove the name from the parent route and add a name to the default child route. @sadraque-santos is the correct answer. Then you use the default child route name to render both the child and the parent for that route.
2

In Vue 2.6.11 you can automatically redirect to a child route if parent route is hit:

const routes = [
  {
    name: 'parent',
    path: '/',
    component: Parent,

    children: [
      {
        name: 'parent.child',
        path: 'child',
        component: Child,
      }
    ],

    /**
    * @type {{name: string} | string} Target component to redirect to
    */
    redirect: {
      name: 'parent.child'
    }
  }
];

Comments

0

When you are using named routes and you want to load the component with your child inside, you have to use the name route for the child.
In your Navigation menu links, if you use name route for the parent, the child will not load automatically, even if the child path is nothing.
Let's say for example we have a User route, and we want to show list of users inside the component by default so whenever we go to '/user' path we want to load a list of users as a child in there:

routes: [
   {
     path: '/user',
     name: 'User',
     component: User,
     children: [
       {path: '', name: 'UserList', component: UserList}, // <== child path is = '';
     ]
   }
  ]

If you think about the code, you might assume if you go to route with name 'User' you might get UserList in there as well, because the path for parent and children both are same. but it's not and you have to choose 'UserList' for the name. Why this is happening? Because Vuejs loads the exact component you are referring to, not the url. you can actually test this, instead of using named route in your links, you can just refer the url, this time vuejs will load the parent and child together with no problem, but when you use named route, it doesn't look at the url and loads the component you are referring to.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.