Introduction to Vue Router Navigation Guards

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

Vue Router is a URL router that maps URLs to components.

In this article, we’ll look at how to add navigation guards to do checks before navigation is done.

Global Before Guards

Router parameter or query changes won’t trigger enter or leave navigation guards.

We can watch the $route object or use the beforeRouteUpdate in-component guard to check those changes.

For other route changes, we can use navigation guards to run checks before navigating to a route.

The beforeEach method takes a callback as follows:

const router = new VueRouter({ ... })  

router.beforeEach((to, from, next) => {  
  // ...  
})
Enter fullscreen mode Exit fullscreen mode

The 3 parameters are the following:

  • to — the target route object being navigated to
  • from — the current route that’s being navigated from
  • next — a function that’s called to resolve the hook

The next function takes one argument. It can take on several possible values.

If nothing is passed in, then we can navigate to the next route. If we pass in false , then the current navigation is aborted.

If we pass in '/' or { path: '/' } , then we redirect to the / route. The current navigation is aborted and a new one is started. We can also set the replace and name properties like as we do with router.push or router.replace .

We can also pass in an Error instance since Vue 2.4.0, then the navigation will be aborted and the error will be passed to callbacks registered via router.onError() .

We should only call next once in our guard.

For example, we can create a navigation guard to check navigation as follows:

src/index.js :

const Login = { template: "<div>login</div>" };  
const Profile = { template: "<div>profile</div>" };  
const routes = [  
  {  
    path: "/",  
    component: Login  
  },  
  {  
    path: "/profile",  
    component: Profile  
  }  
];

const router = new VueRouter({  
  routes  
});

router.beforeEach((to, from, next) => {  
  if (to.path === "/") {  
    return next();  
  } if (!localStorage.getItem("token")) {  
    next("/");  
  } else {  
    next();  
  }  
});

new Vue({  
  el: "#app",  
  router  
});
Enter fullscreen mode Exit fullscreen mode

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

In the code above, our navigation guard first checks if we’re going to / , if we are, then we let them navigate to it.

Otherwise, we check if localStorage.token is defined. If it is, then we let them through. Otherwise, we go back to / .

Therefore, if localStorage.token is defined, then we can go to /#/profile and see profile displayed. Otherwise, we get redirected back to /#/ and see login.

Global Resolve Guards

Vue Router also has router.beforeResolve , which is similar to router.beforeEach but it’s called right before navigation is confirmed, and after all in-component guards and async route components are resolved.

Global After Hooks

We can also run code after navigation is done with the afterEach hook.

For example, we can use it as follows:

src/index.js :

const Foo = { template: "<div>foo</div>" };  
const Bar = { template: "<div>bar</div>" };  
const routes = [  
  {  
    path: "/",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  routes  
});

router.afterEach((to, from) => {  
  alert(`Navigated to ${to.path}`);  
});  
new Vue({  
  el: "#app",  
  router  
});
Enter fullscreen mode Exit fullscreen mode

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="[https://unpkg.com/vue/dist/vue.js](https://unpkg.com/vue/dist/vue.js)"></script>  
    <script src="[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

Then we get an alert box that shows where we navigate to when we navigate.

Note that it doesn’t have the next function in the callback signature because it can’t go to the next route.

Per-Route Guard

We can also define navigation guards per route. For example, we can define it as follows:

src/index.js :

const Login = { template: "<div>login</div>" };  
const Profile = { template: "<div>profile</div>" };  
const routes = [  
  {  
    path: "/",  
    component: Login  
  },  
  {  
    path: "/profile",  
    component: Profile,  
    beforeEnter: (to, from, next) => {  
      if (!localStorage.getItem("token")) {  
        next("/");  
      } else {  
        next();  
      }  
    }  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});
Enter fullscreen mode Exit fullscreen mode

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

The beforeEnter hook for /profile checks if localStorage.token is defined. If it is, then we let them through. Otherwise, we go back to / .

Therefore, if localStorage.token is defined, then we can go to /#/profile and see profile displayed. Otherwise, we get redirected back to /#/ and see login.

The signature is the same as the global beforeEach callback.

Conclusion

We run code before and after navigation with navigation guards.

Before hooks are handy for doing checks before navigation is done. For example, it’s handy for authentication checks.

After hooks are handy for running code after navigation is done.

We can define hooks per route or globally.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .