Vue-router: $router.push({query: this.myarray}) not updating the URL

Created on 20 Feb 2017  路  27Comments  路  Source: vuejs/vue-router

Vue.js / vue-router versions

2.1.2

Reproduction Link

http://jsfiddle.net/ub9e33fm/2/

Steps to reproduce

  1. Click first link
  2. Click second link: see the difference in printed vars

What is Expected?

Clicking the second link will also update this.$route.query

What is actually happening?

this.$route.query is not updated

bug

Most helpful comment

After more debugging, it looks like the issue was that on created() i was assigning a variable, filters to this.$route.query.

As soon as i removed that, setting the query string as my filters object updates works as expected.

The fix was to change my assignment in the created() method to:

this.filters = JSON.parse(JSON.stringify(this.$route.query));

from

this.filters = this.$route.query

Once I did that, I was able to use this.$router.replace({ path: this.$route.params[0], query: filters }); without any issues!

Hopefully this helps someone stuck with this!

All 27 comments

$route.query is updated on next click. Either click twice on second link or after clicking second link, click first link.

@znck any possible hack for this issue?

/ping @posva Could you fix this? Or share a hack!

Seems like a reactivity issue for $route.query. A quick workaround is to pass a copied array each time using arr.slice()
http://jsfiddle.net/gtrasncw/

Unfortunately, the problem remains when property {name} is added to route.push() method:

http://jsfiddle.net/ub9e33fm/12/

Version

2.7.0 (Edge)

Reproduce

  1. Click first link (?q=foo)
  2. Click second link (?=foo,bar)

See the $route.query not being updated with bar

  1. Click second link again. Now you see the updates.
  2. Remove name: 'home' from both this.$router.push lines
  3. Rerun. Now it works.

if this.$router.push query of parameter is array , Could you fixed this? @kvdmolen

Just as @fnlctrl said, pass a copied array instead of the direct reference.

I've just fallen back to using plain Javascript to update the URL after this.$router.push({ query: updatedQuery }), as cloning the object/array doesn't seem to work for me on v3.0.1.

For all those searching in vain, here's the workaround:
window.history.pushState({}, '', 'index.html#/viewName?queryParam=' + this.$route.query.queryParam;

It's not the most glamorous of solutions but it works. I can, moving forward, share the URL and with some changes, return to the view I specified.

@timpalac this is the exact same problem i'm currently dealing with - solved the exact same way. ++ on the solution as it actually works.

Here's an alternate solution that works with back/forward buttons on the browser ... just add a second route with the same component and flip back and forth.

const routes = [ { path: '/results', component: searchResults }, { path: '/result', component: searchResults } ];

I'd really like to see a feature added to update the query string in the URL, it's absurd that I have to hop routes in order to get my query string updated without breaking the browser.

After more debugging, it looks like the issue was that on created() i was assigning a variable, filters to this.$route.query.

As soon as i removed that, setting the query string as my filters object updates works as expected.

The fix was to change my assignment in the created() method to:

this.filters = JSON.parse(JSON.stringify(this.$route.query));

from

this.filters = this.$route.query

Once I did that, I was able to use this.$router.replace({ path: this.$route.params[0], query: filters }); without any issues!

Hopefully this helps someone stuck with this!

Unfortunately that doesn't seem to update the URL to match. Who knows, maybe I'm doing it wrong.

Because a route is immutable (https://router.vuejs.org/en/api/route-object.html) Object.assign() is not able to modify it. FIx: don't try to modify the route object:

query: Object.assign({}, this.$route.query, opt)

(from: https://stackoverflow.com/a/43441772/2112538 )

Ok so this works. Looks like pushing variables to the $router instead of the existing path and query does the trick. Finally, stumbled across something by accident while refactoring :)

let updatedQuery = {
'query1': this.$route.query.query1,
'eventType': this.$route.query.query2
}
let updatedPath = this.$route.path;
this.$router.push({ path: updatedPath, query: updatedQuery });

Why is this closed @kvdmolen ? what's the solution? should this not update the URL?

@francoisromain This is exactly what it is ^_^ made sense and it works like a charm! Thanks 馃憤

@acidjazz Well, as @francoisromain stated, it's an immutable object so it should be used differently than plain objects and such. Doesn't really seems like a bug, though ;)

thanks @kozie and @francoisromain , this ended up working for me as well

  methods: {
    query (params) {
      let query = Object.assign({}, this.$route.query, params)
      this.$router.push({ query: query })
      this.get(query)
    }
  }

For anyone still having a similar problem and who cannot find the cause: perhaps you are reusing the reference to the same array in multiple route objects. Object.assign doesn't do a deep copy. Mutating an array doesn't trigger a route transition and in the subsequent route navigation triggered by router.push / router.replace the check in transitionTo recognizes no change since it compares the array to itself.

The solution is to work with an array like described here: Pure javascript immutable array

But doing a deep copy is a very weird but also reliable way to not have to write your code overly complicated:

JSON.parse(JSON.stringify(this.$route.query)));

@pfeiferbit thanks a lot!
It works for me.

I've just fallen back to using plain Javascript to update the URL after this.$router.push({ query: updatedQuery }), as cloning the object/array doesn't seem to work for me on v3.0.1.

For all those searching in vain, here's the workaround:
window.history.pushState({}, '', 'index.html#/viewName?queryParam=' + this.$route.query.queryParam;

It's not the most glamorous of solutions but it works. I can, moving forward, share the URL and with some changes, return to the view I specified.

this.$router.push({name:'posts', query: { page: this.$route.query.page }}); this works for me.

After more debugging, it looks like the issue was that on created() i was assigning a variable, filters to this.$route.query.

As soon as i removed that, setting the query string as my filters object updates works as expected.

The fix was to change my assignment in the created() method to:

this.filters = JSON.parse(JSON.stringify(this.$route.query));

from

this.filters = this.$route.query

Once I did that, I was able to use this.$router.replace({ path: this.$route.params[0], query: filters }); without any issues!

Hopefully this helps someone stuck with this!

This is still the correct answer for me. Seems like a bug.

I just can't router.replace({ query: {} })! Replacing to existing name or path works, query doesn't. What am I doing wrong, guys? I want to remove query string.

If anyone is still having this issue, I am using following code as a solution:

if (Object.entries(this.$route.query).length !== 0 
    && this.$route.query.constructor === Object) {
  this.$router.replace({ query: {} });
 }

I'm having this issue with 3.8.4, not doing anything fancy, just updating with query param (no arrays, a completely new object). Keeping everything the same and navigating to a different route correctly applies query params, doing push for the same route with new query params does nothing.

cc @posva

I ended up implementing a refresh route for now, going to it with new query redirects back with those new query params.

export default {
  name: "refresh",
  beforeRouteEnter(to, from, next) {
    next((instance) => {
      instance.$router.replace({
        name: from.name,
        params: from.params,
        query: to.query
      });
    })
  },
};

Ok, scratch everything above, in my case it was a missing next() call in on the beforeRouteUpdate hook in the original route

beforeRouteUpdate(to, from, next) {
  this.rerender();
},

after I did this

beforeRouteUpdate(to, from, next) {
  this.rerender();
  next();
}

things started working.

Not sure if possible, but some warning in console about not called next (like after several seconds) would be helpful for a newbie as myself.

Locking as the issue is quite old and multiple conversations are getting mixed up

Not sure if possible, but some warning in console about not called next (like after several seconds) would be helpful for a newbie as myself.

It's not possible because a guard can be async and take a long time

Was this page helpful?
0 / 5 - 0 ratings