234

On my main page I have dropdowns that show v-show=show by clicking on the link @click = "show=!show" and I want to set show=false when I change the route. Please advise me on how to realize this thing.

Asef Hossini
  • 655
  • 8
  • 11
kipris
  • 2,899
  • 3
  • 20
  • 28

12 Answers12

475

Setup a watcher on the $route in your component like this:

watch:{
    $route (to, from){
        this.show = false;
    }
} 

This observes for route changes and when changed ,sets show to false

tony19
  • 125,647
  • 18
  • 229
  • 307
Vamsi Krishna
  • 30,568
  • 8
  • 70
  • 78
61

If you are using v2.2.0 then there is one more option available to detect changes in $routes.

To react to params changes in the same component, you can watch the $route object:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // react to route changes...
    }
  }
}

Or, use the beforeRouteUpdate guard introduced in 2.2:

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

Reference: https://router.vuejs.org/en/essentials/dynamic-matching.html

Kees de Kooter
  • 7,078
  • 5
  • 38
  • 45
Shubham Nigam
  • 3,844
  • 19
  • 32
52

Just in case anyone is looking for how to do it in Typescript, here is the solution:

@Watch('$route', { immediate: true, deep: true })
onUrlChange(newVal: Route) {
    // Some action
}

And yes as mentioned by @Coops below, please do not forget to include :

import { Watch } from 'vue-property-decorator';

Edit: Alcalyn made a very good point of using Route type instead of using any:

import { Watch } from 'vue-property-decorator';    
import { Route } from 'vue-router';
SoyChai
  • 320
  • 2
  • 11
ATHER
  • 3,254
  • 5
  • 40
  • 63
  • 3
    Don't forget to include in the import: `import { Prop, Watch } from "vue-property-decorator";` – Paul C Aug 13 '19 at 16:13
  • 1
    I took me hours to finally realize that, any documentation out there? – Ayyash Jan 10 '20 at 11:07
  • 1
    Similar doc I can find: https://router.vuejs.org/api/#the-route-object Also instead of using the `any` type, you may want to use the interface `Route` from `import { Route } from 'vue-router';` – Alcalyn Jan 21 '20 at 14:04
22

Watcher with the deep option didn't work for me.

Instead, I use updated() lifecycle hook which gets executed everytime the component's data changes. Just use it like you do with mounted().

mounted() {
   /* to be executed when mounted */
},
updated() {
   console.log(this.$route)
}

For your reference, visit the documentation.

tony19
  • 125,647
  • 18
  • 229
  • 307
12

Using Vue3 and the composition API you can do

<script setup lang="ts">
import { watch } from "vue";
import { useRoute } from "vue-router";

const route = useRoute();

// do a `console.log(route)` to see route attributes (fullPath, hash, params, path...)
watch(
  () => route.fullPath,
  async () => {
    console.log("route fullPath updated", route.fullPath);
  }
);
</script>

References and examples here: https://router.vuejs.org/guide/advanced/composition-api.html#vue-router-and-the-composition-api

8

UPDATE

As stated by @CHANist, router.listen no longer works, I don't know from which version it stopped working, but the good news (as also stated by @CHANist) is we can use:

this.$router.history.listen((newLocation) => {console.log(newLocation);})

OLD Response

The above responses are the better, but just for completeness, when you are in a component you can access the history object inside the VueRouter with: this.$router.history. That means we can listen to changes with:

this.$router.listen((newLocation) => {console.log(newLocation);})

I think this is mainly useful when used along with this.$router.currentRoute.path You can check what I am talking about placing a debugger

instruction in your code and begin playing with the Chrome DevTools Console.

Melardev
  • 1,101
  • 10
  • 22
  • downvoted because I get error this.$router.listen is not a function – null canvas Nov 03 '20 at 12:42
  • @AngJobsonGithub Hi, from where are you calling this, this.$router will only be accessible on a Vue component, are you calling it from somewhere else? such as fetch()? – Melardev Nov 04 '20 at 13:07
  • I think the call was inside a vue file, this.$router is available but not the `listen` function. – null canvas Nov 06 '20 at 05:38
  • @AngJobsonGithub It has to be called from within a Vue component, "this" should be a Vue Component and the project should be using VueRouter – Melardev Nov 06 '20 at 07:49
  • 1
    The code mentioned above seems does not work in Vue 2.6.11. The code need to change to the following `this.$router.history.listen((newLocation) =>{console.log(newLocation);})` in order to make it work. Thanks for the answer. – CHANist Apr 05 '21 at 07:25
8

import { useRouter } from "vue-router";

const router = useRouter();

router.afterEach((to, from) => { });

Reza Mahmoodi
  • 170
  • 1
  • 5
3

Another solution for typescript user:

import Vue from "vue";
import Component from "vue-class-component";

@Component({
  beforeRouteLeave(to, from, next) {
    // incase if you want to access `this`
    // const self = this as any;
    next();
  }
})

export default class ComponentName extends Vue {}
Delowar Hosain
  • 2,214
  • 4
  • 18
  • 35
2

I hope you doing well, in vue3 and script setup this work is too easy:

watch(route, () => { fetch()})

be careful you must import before

import { watch } from 'vue';
import { useRoute } from 'vue-router';

and define use route :

const route = useRoute()
Pirooz Jenabi
  • 440
  • 5
  • 7
1

using Vue Router is an alternative way, use the beforeRouteLeave after methods in your component like this:

<template>
   <button @click="ShowMethod">DisplayButton</button>
</template>
<script>
  data() {
    return { show: true };
   },
   methods: {
   ShowMethod() {
   this.show = false;
    }
   },
   beforeRouteLeave(to, from, next) {
   this.show = false;
   next();
 }
</script>

according to VueJs documentation, it's called Navigation Guards check the link below:

Navigation Guards

The leave guard is usually used to prevent the user from accidentally leaving the route with unsaved edits. The navigation can be canceled by calling

In-Component Guards:

beforeRouteEnter

beforeRouteUpdate

beforeRouteLeave

  beforeRouteLeave(to, from, next) {
// called when the route that renders this component is about to
// be navigated away from.
// has access to `this` component instance.
 }

look at the below link for more information:

In-Component Guards

pedram
  • 181
  • 2
  • 8
1

Using the Vue.js option API, this is how you can watch for changes on anything (like $route.path). In this piece of code, when the component is mounted, it will watch for changes in the path:

export default{
   mounted(){
      this.$watch( ()=> this.$route.path,(to, from)=> {
         console.log('route path has changed from ' +from+' to '+to )
      })   
   }
}
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Neo Mn
  • 150
  • 1
  • 12
0

you can use the beforeEach event which allows any function to occur when the route is changing, just don't forget to call the next() function to proceed next operation, basically it has the same job as the backend expressJS middleWare.

router.beforeEach((to, from, next) => {
  store.commit('setError', null); //in this example on each route I'm removing the error noted from the old route
  document.title = `${to.meta.title} | HartWork`; //on each route I'm adding a prefix to document title.
  next(); //calling next to proceed next functions and operations
})
moghwan
  • 1,829
  • 2
  • 17
  • 29