typescriptvue.jsvue-router

How to avoid hard-coding parameter names for usage with a query in vue-router


Currently I save a parameter to URL like this:

  const save = async (parameter: LocationQuery) => {
    await router.push({ path: '', query: { ...route.query, ...parameter } });
  };

called like this:

save({ param1: 'abc' });

I also read and monitor the parameters like this:

const route = useRoute();
const x = route.query.param1;
const y = computed(() => route.query.param1);

But I have quite a few query parameters in various features/parts of the code, so having these bits of code in various places is not ideal. I would like to standardize usage, so that I don't have hard-coded names in various places.

So if I create an enum with the parameter names:

export enum QueryParams {
  Param1 = 'param1',
  Param2 = 'param2'
  // ...
}

I can use it for reading and monitoring:

const route = useRoute();
const x = route.query[QueryParams.Param1 as string];
const y = computed(() => route.query[QueryParams.Param1 as string]);

But how do I use the name in the save? I.e.:

const save = async (name: QueryParams, value: string | number | undefined) => {
    const parameter = // HOW to construct this parameter?
    await router.push({ path: '', query: { ...route.query, ...parameter } });
  };

This obviously is wrong:

const parameter = { name: value }; // would creates 'name=' parameter instead of 'param1='

So is there a way to use an enum value to construct a LocationQuery param? If not, is there a better approach that allows to avoid hard-coding query parameter names?

Thanks in advance.


Solution

  • A single dynamic query parameter (name) can be changed with computed property syntax:

    router.push({ path: '', query: { ...route.query, [name]: value } })
    

    If there are many such parameters that affect application state, this could indicate a problem with design. Generally global state doesn't need to be passed through url, it can be stored in a global store, for instance, and can be persisted in browser storage.

    In case the intention is to not be tied to specific client's browser and be able to provide a state through a link, this still could be achieved with global state. Instead of explicitly providing query parameters, the state could be used as a single source of truth, myState.param1 = 'abc'. And it could be implicitly synchronized with route url. It's unknown if router.push serves some purpose besides updating query parameters but they could be updated in myState watcher or router beforeEach/beforeEnter hooks, depending on how this is supposed to work.