3
votes

I have an app where a component, Foo, is used as a template for a route, app/foo. This component has child components which are also used as templates for routes: app/foo/bar, app/foo/baz, etc.

I am binding a global vuex store object to the query property of the route so that if the object is set to, say, { a: 1, b: 2 }, the url params will change to ?a=1&b=2; and if the user changes the params to, say, ?a=0&b=0, the object will update to be { a: 0, b: 0 }. This is all working as expected.

The trouble I'm having is that, when I then route to any path under app/foo, I lose the route's query property and the url params disappear.

I can pass the query object dynamically like so:

this.$router.push({ name: 'bar', query: this.$route.query });

But, this is quickly getting hard to maintain.

I know Vue Router provides added life-cycle events, and I thought I should be able to update the query on the Foo component's beforeRouteUpdate event. I've made a few different attempts, but no dice:

beforeRouteUpdate (to, from, next) {
  // This gives me an error saying that the query is read-only 
  to.query = from.query; 

  // This does not update the query
  this.$router.replace({ query: from.query })

  next();
}, 

Edit:

I also tried setting a watcher on $route to replace the query when the route changes. However, this causes an infinite loop:

watch: {
  $route(to, from) {
    this.$router.replace({ query: from.query });
  }
}

Does anyone know a way to make the Vue Router query persistent at a component-level?

1
Can you add a watcher for the route change and set the query there? see the "Reacting to Param Changes" section on this pagecraig_h
Good suggestion. I'm trying this, but there are still some cases where the url params are cleared and I'm investigating why.thanksd
There is an infinite loop issue when updating the $route in the $route watcher (see edit). Even when adding certain checks (to.path != from.path), there is some undesirable behavior. But I'll make an answer with my current (unideal) solution based on your comment. Thanks!thanksd

1 Answers

1
votes

Based on @craig_h's comment, I added a watcher on $route:

watch: {
  $route(to, from) {
    if (to.path != from.path) { // to prevent an infinite loop
      this.$router.replace({ query: from.query })
    }
  }
}

This will work for most cases, except in the case that a component incidentally routes to the current route. In this case, the query is still lost because the to.path and from.path values are the same.

My workaround for that is to add checks to those components that might route to the current route:

if ((name != this.$route.name) || (params != this.$route.params)) {
  this.$router.push({ name, params });
}

This works but is still not ideal.