Options
All
  • Public
  • Public/Protected
  • All
Menu

@oarepo/vue-query-synchronizer

This is Vue 3 implementation, for vue2 look at the vue-2 branch

In browser applications, address bar should be the most important source of truth. When user performs data filtering, sorting, pagination, the url should change so that the result of the filtering is bookmarkable/shareable.

Traditionally vue component would listen on query change and copy the query params to an internal model. This would be then used by an input component. Whenever the input is changed, an event listener (after optional debouncing) would propagate the change back to the query.

This library does all of this on the background, leaving you with just a couple of lines of code.

Installation

yarn add @oarepo/vue-query-synchronizer@^3.0.0

From sources

yarn build
cd dist; yarn link

cd your_project
yarn link @oarepo/vue-query-synchronizer

Usage

Plugin installation

Add the following to main.js (in quasar boot/....js)

import QuerySynchronizer from '@oarepo/vue-query-synchronizer'

Vue.use(QuerySynchronizer, {
    router: router
})

See src/main.ts for the whole file.

Router configuration

In router configuration, mark which query parameters with a given type and default value should be synchronized with the component state:

import { query } from '@oarepo/vue-query-synchronizer'

const routes = [
{
    path: '/',
    name: 'home',
    meta: {
        query: {
           'page': 'int:1'
        }
    },
    component: Home
}
]

Full example at src/router.ts

Component

Composition-api based

Call useQuery() and use the result as usual (for example as model for input):

<template>
<div>
    <input v-model="query.filter"><br><br>
</div>
</template>

<script>
import { useQuery } from '@oarepo/vue-query-synchronizer'

export default {
    setup() {
      return {
        query: useQuery(),
      }
    }
}
</script>

Full example at src/CompositionHome.vue

Options-based component

In component, use this.$query to access parsed query. Then you can use properties at $query, for example $query.filter, $query.sort as normal models for html inputs or as models for any other components:

<template>
<div>
    <input v-model="$query.filter"><br><br>
</div>
</template>

<script>
export default {
    name: 'home',
}
</script>

Full example at src/Home.vue

Demo setup and run

yarn install
yarn run serve

Screenshot

screenshot

Library build

yarn run build

API

QuerySynchronizer plugin configuration

During plugin registration, router must be passed in.

import QuerySynchronizer from '@oarepo/vue-query-synchronizer'

Vue.use(QuerySynchronizer, {
    router: router,
    datatypes: {
        name: handler
    },
    debug: false,
    navigationOperation
})

Setting debug to true will log the parsed and serialized query parameters.

Route meta definition

The potential query parameters with data types are stored in route's meta.query property in the form of param_name:definition.

definition

Definition can be:

  • default string value (test)
  • datatype followed by a default value (int:1)
  • an object:
{
    datatype: 'string',
    defaultValue: null
}

The object can define a datatype, which is implicitly string. The datatype defines how the value from URL is converted to model and vice versa. Datatypes are pluggable, see Datatype section later in the readme for details.

If defaultValue is set and a value is not present in the URL, the model is set to this value. URL is not changed. When a default value is programmatically set on the parameter (for example, user enters it in input), the parameter is removed from the url.

Note: This means that if you change the default value of a parameter during the lifetime of your application, user's bookmarks will start behaving differently as your code will receive the new default values, not the ones used when user bookmarked the page.

Datatype

A datatype provides means to convert url parameter into an internal model value and vice versa. The pre-installed datatypes are:

  • string - a no-op converter
  • number - converts string value of the number in url into a javascript number
  • bool - if the parameter is present (with whatever value), returns true else false
  • array - returns an array of string (for parameters with multiple values)

A custom datatype can be implemented as follows:


Vue.use(QuerySynchronizer, {
    router: router,
    datatypes: {
        lowecase: {
            parseDefault(value) {
                // parses the default value from the strings above
                return (value || '').toLowerCase()
            },
            parse(value, defaultValue) {
                // value is: undefined if property is not present in the url
                // null if property is in url but without a value
                // string value if property is written as url?key=value
 
                // note: defaultValue has been parsed previously so that
                // it already is in the javascript format
                return value ? value.toLowerCase() : defaultValue 
            },
            serialize (value, defaultValue) {
                // this method must return undefined, null or string instance
                // returning undefined will remove the property from query
                if (value === defaultValue) { return undefined }
                // returning null will put url?key without a value to the url
                if (value === '') { return null }
                // will put url?key=value into the url
                return value.toLowerCase()
            }
        }
    }
})

Default datatypes are implemented by importable StringDatatype, IntDatatype, BoolDatatype, ArrayDatatype.

You can use them to create composite datatypes, for example an array of numbers.

ArrayOfNumbersDatatype = {
    parseDefault(value) {
        return ArrayDatatype.parseDefault(value).map(
            x => IntDatatype.parse(x, null)
        )
    },
    parse(value, defaultValue) {
        return ArrayDatatype.parse(value, defaultValue).
            map(x=>IntDatatype.parse(x, null))
    },
    serialize (value, defaultValue) {
        return ArrayDatatype.serialize(
            value.map(x => NumberDataType.serialize(value, null)),
            defaultValue)
    }
}

Callbacks and signals

The following signals can be specified at the query level:

import { query } from '@oarepo/vue-query-synchronizer'

const routes = [
{
    path: '/',
    name: 'home',
    meta: {
        query: {...},
        querySettings: {
            onInit (paramsList) { paramsList },
            onLoad (query) { /* do something with query */ },
            onChange (newQuery, query) { /* do something with newQuery */ }
        }
    },
    component: Home
}
]

onInit

onInit is called when the query is loaded. This signal can be used for example to set default values stored in local storage or on the server.

onLoad

called after browser query parameters are parsed and before they are returned to the component.

onChange

called after just before the url is changed. Can be used to store the values to local storage so that the next onInit picks them and uses them as default. The callback takes two parameters:

  • newQuery is the new query that will be set to URL. Does not contain props with default values
  • query contains the whole current query object with resolved default values

API docs

See docs

Index

Type aliases

GenericParsedQuery

GenericParsedQuery: {}

If not defined otherwise, the returned query is of this generic type

Type declaration

  • [key: string]: string | number | string[] | number[] | boolean | any

NavigationOperation

NavigationOperation: "replace" | "push" | ((query: ParsedQuery, router: Router) => "push" | "replace")

ParsedQueryMixin

ParsedQueryMixin: { addValue: any; define: any; removeValue: any }

Query returned by useQuery() is not only an object with parsed query parameters, but contains several helper methods defined in this mixin.

Type declaration

  • addValue: function
    • addValue(key: string, value: any, datatype?: DataType<any>): void
    • Adds a value to array parameter, making sure that it is added only once

      Parameters

      • key: string

        name of the URL parameter

      • value: any

        the value

      • Optional datatype: DataType<any>

        optional datatype, used only if the parameter's datatype is not yet an array

      Returns void

  • define: function
    • define(key: string, datatype: DataType<any>, defaultValue: any): void
    • Dynamically add a new query parameter. If the parameter is already known, its datatype will be replaced and the parameter will be parsed again.

      Parameters

      • key: string

        name of the URL parameter

      • datatype: DataType<any>

        datatype of the parameter

      • defaultValue: any

        the default value

      Returns void

  • removeValue: function
    • removeValue(key: string, value: any, datatype?: DataType<any>): void
    • Removes a value from array parameter

      Parameters

      • key: string

        name of the URL parameter

      • value: any

        the value

      • Optional datatype: DataType<any>

        optional datatype, used only if the parameter's datatype is not yet an array

      Returns void

TypedParsedQuery

TypedParsedQuery<T>: ParsedQueryMixin & T

User can type the result of useQuery with his own type. In this case the return value is TypedParsedQuery

Type parameters

  • T

Variables

Const ArrayDatatype

ArrayDatatype: DataType<string[]> = ...

Interprets URL parameter as an array of strings, that is the parameter might be present multiple times

Const BoolDatatype

BoolDatatype: DataType<boolean> = ...

Interprets URL parameter as boolean. If the parameter is present the value is true, false otherwise

Const CommaArrayDatatype

CommaArrayDatatype: DataType<string[]> = ...

parses param=v1,v2,v3,... into [v1,v2,v3] string array

Const IntDatatype

IntDatatype: DataType<number> = ...

Interprets URL parameter as integer

Const SpaceArrayDatatype

SpaceArrayDatatype: DataType<string[]> = ...

parses param=v1%20v2%20v3... into [v1,v2,v3] string array

Const StringDatatype

StringDatatype: DataType<string> = ...

Parses URL parameter as string

Const default

default: { install: any } = ...

Vue plugin. Usage:

createApp(App).use(router).use(QuerySynchronizer, { router, debug: true })
param

application's router

param

an optional array of custom (user-defined) datatypes

param

if set to true, print library's debug messages

Type declaration

  • install: function
    • install(app: any, __namedParameters: { datatypes?: DataType<any>[]; debug?: boolean; navigationOperation?: "replace" | "push" | ((query: ParsedQuery, router: Router) => "replace" | "push"); router: Router }): void
    • Parameters

      • app: any
      • __namedParameters: { datatypes?: DataType<any>[]; debug?: boolean; navigationOperation?: "replace" | "push" | ((query: ParsedQuery, router: Router) => "replace" | "push"); router: Router }
        • Optional datatypes?: DataType<any>[]
        • Optional debug?: boolean
        • Optional navigationOperation?: "replace" | "push" | ((query: ParsedQuery, router: Router) => "replace" | "push")
        • router: Router

      Returns void

Functions

separatedArrayDatatype

  • separatedArrayDatatype(separator: string): DataType<string[]>
  • Helper function to generate a new datatype that is an array of strings but serialized within one param=value url parameter with values separated by the given separator

    Parameters

    • separator: string

    Returns DataType<string[]>

useQuery

  • The main composition API entrypoint. Returns a reactive Query object with parsed values

    Type parameters

    • T = GenericParsedQuery

      The type of the returned query object. An interface defining query parameters and their types might be passed. If not a generic (untyped) interface is used.

    Returns TypedParsedQuery<T>

Legend

  • Property
  • Method

Generated using TypeDoc