How to prevent browser refresh, URL changes, or route navigation in Vue
Tags: development, javascript, vue, frontend
Published: 2019-11-06 01:17:41

---
title: How to prevent browser refresh, URL changes, or route navigation in Vue
published: true
date: 2019-10-03 15:03:29 UTC
tags: Development,JavaScript,Vue.js,frontend
canonical_url: https://stegosource.com/prevent-browser-refresh-url-changes-route-navigation-vue/
cover_image: https://stegosource.com/wp-content/uploads/navitagion-1080x720.jpg
---

Every once in a while in [Vue](https://vuejs.org/), you want to prevent the user from navigating away from a route or reloading the page. For example, perhaps they made changes to a form without saving.

This behavior is not immediately available, but it’s relatively easy to accomplish.

First, we’ll need some sort of condition to track whether or not the user can navigate away. It may be different in your case, but for this example, we’ll have a boolean tracking whether the user is editing something.

```
<script>
export default {
  data: () => ({
    isEditing: false
  })
</script>
```

## Prevent URL change and/or page reload.

Next, we need to add some logic to prevent the user from going to a new URL, or reloading the page while our `isEditing` is true. Fortunately, the browser has a native `beforeunload` event just for this.

We’ll add it to the `beforeMount` hook so that we know we are not in a server-rendered environment:

```
<script>
export default {
  // ...
  beforeMount() {
    window.addEventListener("beforeunload", () => {
      if (!this.isEditing) return
      e.preventDefault()
      // Chrome requires returnValue to be set.
      e.returnValue = ""
    })
  }
}
</script>
```

Vue does a great job of [automatically removing any event handlers](https://vuejs.org/v2/guide/events.html#Why-Listeners-in-HTML) that are added to the template, but any that we manually create should be cleaned up to avoid any memory leaks.

To do so, we will refactor our anonymous function into a named method so we can clean it up in the `beforeDestroy` hook:

```
<script>
export default {
  // ...
  beforeMount() {
    window.addEventListener("beforeunload", this.preventNav)
  },

  beforeDestroy() {
    window.removeEventListener("beforeunload", this.preventNav);
  },

  methods: {
    preventNav(event) {
      if (!this.isEditing) return
      event.preventDefault()
      event.returnValue = ""
    }
  }
}
</script>
```

If you prefer, you could also put the event listener logic together by using Vue’s `$once` method:

```
<script>
export default {
  // ...
  beforeMount() {
    window.addEventListener("beforeunload", this.preventNav)
    this.$once("hook:beforeDestroy", () => {
      window.removeEventListener("beforeunload", this.preventNav);
    })
  },

  methods: {
    preventNav(event) {
      if (!this.isEditing) return
      event.preventDefault()
      event.returnValue = ""
    }
  }
}
</script>
```

## Prevent router navigation

Great! So far, our component will prevent a user accidentally losing their changes if the browser changes, but it’s likely that your route changes are actually handled by JavaScript. If that’s the case, you will also need to prevent the Vue router from navigating away.

For this, we can conveniently hook into the [in-component navigation guard](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards) `beforeRouteLeave` (assuming you are using `vue-router`).

`beforeRouteLeave`, as the name implies, runs whenever you are about to navigate away from the current route. It provides us a few parameters to work with:

- `to`: the route being navigated to.
- `from`: the route you are about to leave.
- `next`: th function used to invoke navigation. You can also use this to navigate to any other route you like.

For our purposes, we are only interested in the `next` parameter, and we can combine this with a `confirm` check to ask the user if they want to continue navigation:

```
<script>
export default {
  // ...
  beforeRouteLeave(to, from, next) {
    if (this.isEditing) {
      if (!window.confirm("Leave without saving?")) {
        return;
      }
    }
    next();
  }
}
</script>
```

## Finishing up

With that, we have a nice little component that prevents a user from navigating away based on our logic. Of course, we did not actually implement any logic, but I will leave that up to you.

The whole thing looks like this:

```
<script>
export default {
  data: () => ({
    isEditing: false
  }),

  beforeMount() {
    window.addEventListener("beforeunload", this.preventNav)
    this.$once("hook:beforeDestroy", () => {
      window.removeEventListener("beforeunload", this.preventNav);
    })
  },

  beforeRouteLeave(to, from, next) {
    if (this.isEditing) {
      if (!window.confirm("Leave without saving?")) {
        return;
      }
    }
    next();
  },

  methods: {
    preventNav(e) {
      if (!this.isEditing) return
      e.preventDefault()
      e.returnValue = ""
    },
  },
}
</script>
```

You can see a working example here:

<iframe src="https://codesandbox.io/embed/prevent-page-navigation-in-vue-jq86h?fontsize=14&amp;hidenavigation=1&amp;moduleview=1&amp;view=preview" title="Prevent page navigation in Vue" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>

As a next step, this could be a good candidate for a `mixin`. And if it’s the sort of thing you would like available in [Vuetensils](https://vuetensils.stegosource.com/), let me know.