SteGriff

Blog

Next & Previous

Get vue-router to change part of the query string without a page refresh

People use vue-router in Vue Single Page Apps (SPAs) to manage how the URL affects what you’re seeing on the page.

Sometimes you want to change or remove some part of the query string (?origin=SOP&destination=LPL), but not the whole thing. Vue-router is a little tricky about this because the $route.query object is immutable - you cannot mutate it.

Vue-router’s API for modifying the current route (URL) accepts a ‘location’ object which can specify a path, a named route via name, route params, and a query object. We’ll just play with the query.

N.b. In a Vue component, you always have access to the router via this.$router. Elsewhere, you have to import router from 'vue-router'. I’ll use the former for examples.

Now if you want to modify the query in response to a changing field, you might try this:

watch: {
  userOrigin() {
    this.update();
  },
  userDestination() {
    this.update();
  }
},
methods: {
  update() {
    let queries = this.$route.query;
    queries.origin = this.userOrigin;
    queries.destination = this.userDestination;
    this.$router.replace({ query: queries });
  }
}

…and you would expect the URL to change. But it won’t work.

You can’t make direct changes to the this.$route.query object by reference. You have to make a copy of it.

Now, there is a popular but ugly trick for making a naive deep clone of an object in JS, which is to serialize it to JSON then immediately deserialize the resulting string. To anyone who doesn’t know why you’re doing that, you’ll look completely stupid. Best to leave a comment 😉

This will work:

methods: {
  update() {
    // Make a clean copy of the current query
    let queries = JSON.parse(JSON.stringify(this.$route.query));
    queries.origin = this.userOrigin;
    queries.destination = this.userDestination;
    this.$router.replace({ query: queries });
  }
}

So, in short, you can’t make changes to this.$route.query, or any reference to it (let queries = this.$route.query still points to the same object). So to mutate the route, you have to clone the query, with a technique like the above.

Hope it helps 😄