nos
nos

Reputation: 20880

How to use vue-router to redirect to 404 page with invalid URL parameter

I use vue-router to navigate the user pages by their user id. And the router.js looks like as follows

export default new Router({ 
  mode: 'history', 
  base: process.env.BASE_URL, 
  routes: [ 
    { 
      path: '/user/:id',
      name: 'user',  
      component: () =>  
        import(/* webpackChunkName: "user" */ './views/User.vue'),
      props: true               
    },
    {
      path: '/404', 
      name: '404',
      component: () => import('./views/404.vue'),
    },
  ] 
}) 

If someone go to the URL of /user/some-invalid-id, how do I redirect it to the 404 page?

In my app, all user data is loaded at the App.js' breforecreate(), and internally the User view is accessed as follows for existing users

<router-link :to="{name: 'user', params:{id: u.pk}}" >                  
  <a> {{u.first_name}} {{u.last_name}} </a>                             
</router-link> 

I know it's possible to redirect programmatically with a push function call. But I don't know where this code should be used.

this.$router.push('/404') 

In the User.vue view page, I use a vuex getter called userByID to retrieve data.

userByID: (state) => id => {
    return state.users.find(u => (u.pk == id))
}

Should router.push('/404') happen in userByID or its caller? How do we deal with the template rendering with undefined user object?

Upvotes: 2

Views: 6174

Answers (1)

Jim B.
Jim B.

Reputation: 4714

I think you want to use 'Navigation Guards`, specifically a beforeEnter hook in your /user/:id route.

Something sort of like this (not tested; just directional):

routes: [ 
    { 
        path: '/user/:id',
        name: 'user',  
        component: () =>  
            import(/* webpackChunkName: "user" */ './views/User.vue'),
        props: true,               
        beforeEnter: (to, from, next) => {
            if (!userById($route.params.id)) {
                next('/404'); 
            }
            else {
                next();
            }
        }        
  }
    },
    {
        path: '/404', 
        name: '404',
        component: () => import('./views/404.vue'),
    },
  ] 

Note that you'll need to be able to determine if the user is valid without invoking the User.vue component.

You can also implement a beforeRouteEnter hook on User.vue directly, though you'll not be able to call other User.vue methods there as the component won't yet be mounted.

More on navigation guards: https://router.vuejs.org/guide/advanced/navigation-guards.html#global-guards

Given your userById method is accessing the store, I found this post that might help you access the store in your beforeEnter method: How to access async store data in vue-router for usage in beforeEnter hook?

Upvotes: 2

Related Questions