1
votes

I've got kind of a toy project started using vue and vue router, but I am stuck on getting query params. My setup might be unusual from what I've read... I don't use npm or the vue cli, I don't build or minify. Just like this to get started...

// public/index.html

<head>
    <!-- some other includes like this -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.31/vue.global.prod.min.js" integrity="sha512-aHDp6BDlnbRLDTxmY5GIqQA0RQd6dmeKIDDDiEJlRrKNQPZbo2mjsR/DGMUzupcCpE4XgPyeIPnDQdJNUmeEhw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/4.0.13/vue-router.global.prod.min.js" integrity="sha512-RfYSruXiMtNZ9MzGNmxl3ljuCJsnlgj/KFabVMUh/gla9c7mjyggP9iTwFtrGYJhi0Qw7J3z0VMSeLRsNT92Fg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="./index.js" type="module"></script>
  </head>

Then I setup my router like this...

// public/index.js

import Play from './play.js'
import Settings from './settings.js'
// others

const routes = [
  { path: '/play', component: Play },
  { path: '/settings', component: Settings },
  // others...
  { path: '/:pathMatch(.*)*', redirect: '/play' }
];

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes,
});

// and later
const app = Vue.createApp(App);
app.use(router);
app.mount('main');

This is fine, and routing works fine in my app. My app launches, and I can navigate to play this way: (Note, this is using vscode and liveserver plugin, with config to start on port 5500 in /public)

http://localhost:5500/#/play

It works! And I can go to http://localhost:5500/#/settings and see my settings vue just fine. The problem is that I can't see query params. For example, I'd like to pass gameId=xyz123 to my play vue. When I enter this into the chrome address bar:

 http://localhost:5500/#/play?gameId=xyz123

and press "return". The first thing that happens is nothing. When I press return a second time, the next thing that happens is the browser navigates to http://localhost:5500/#/play (no query params). In my vue, I check route query params and always get nothing. It seems by the time this vue loads, some part of the system has changed the URL to exclude the query.

// public/play.js

mounted () {
  const gameId = this.$route.query.gameId;
  console.log(gameId); // always logs nothing
}

I've tried a LOT of stuff:

  1. use createWebHistory() (no hash)... all the routing breaks then, with my browser saying "Can't GET /play"
  2. use older 'history' mode from vue router 2.x. It seems to be no longer present, and I can't downgrade router without downgrading vue.
  3. Change from query params to route params. I tried defining route like 'play/:gameId' but with the very same effect
  4. Don't use live server - I deployed to firebase hosting and tried query params there. I can't see as much without the vscode debugger, but the behavior appeared the same.
  5. Try without that *.* path match, thinking maybe that's what re-writes the URL. Nope - same behavior.

I'm stuck, and from googling, it doesn't seem like anyone else has complained about this in a way that matches my problem. Much obliged for any help.

2
I had some similar problems. I observed that the query parameters are only available in the component on the exact match of the route. However, from your question, this seems the case already. I managed to get a solution for me, if you want to look at github.com/suterma/replayer-pwa/blob/…Marcel
Thanks @Marcel - I'll study it.goodson

2 Answers

0
votes

For the next poor lost soul who wanders here: I fixed by changing things as follows to match better with suggestions from the vue router docs.

(1) Name the routes, use params, not query, use the props option

e.g.

{ name: 'play', path: '/play/:id?', component: Play, props: true },

(2) The above means that the vues need to have props defined, and those will take on the values of the route params...

// play.js

export default {
  template,
  props: ['id'],
  // ...

(3) watch those props

  watch: {
    id(newId, oldId) {
      if (newId) this.play(newId);
    }
  },

(4) Not sure it matters, but since I had the routes named, I started navigation by name...

this.$router.push('settings', params: { id: someId });

My theory about why this way works is this: when I was navigating to the same route with a different query string, the vue was already mounted, and some combination of vue / router decided it shouldn't mount again. The watched prop give me a way to not depend on the lifecycle methods.

0
votes

You use routes, so your query will only be available from inside of a routed view.

In App.vue you will have something like:

<template>
    ...     
        <!-- To keep the audio within the media player component running, 
        simply keep this component alive over route changes -->         
        <router-view v-slot="{ Component }">
            <keep-alive include="Play">
                <component :is="Component" />
            </keep-alive>
        </router-view>
    ... 
</template>

Then, inside the Play.vue component you get access to the query part of the route.

If you have e.g:

http://localhost:8080/#/play?media=https%3A%2F%2Fweb.replayer.app%2Fyour-light-by-lidija-roos.mp3&title=Your%20Light&artist=Lidija%20Roos&album=Not%20For%20Sale&6.49=Intro

Then in Play.vue or a sub-component on it you can do:

const query = this.$route?.query;

to get access to the query:

{
    "media": "https://web.replayer.app/your-light-by-lidija-roos.mp3",
    "title": "Your Light",
    "artist": "Lidija Roos",
    "album": "Not For Sale",
    "6.49": "Intro"
}