Introduction to Vue Router Navigation Guards
Tags: vue, webdev, programming, javascript
Published: 2021-01-25 23:22:25

**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) => {  
  // ...  
})
```

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  
});
```

`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>
```

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  
});
```

`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>
```

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  
});
```

`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>
```

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.