UNPKG

@veebisepad/vue-query-filters

Version:

Reactive utility for managing URL query parameters in Vue 3.

329 lines (262 loc) 10.2 kB
# Vue Query Filters A lightweight, flexible URL query parameter management system for Vue applications. [![npm version](https://img.shields.io/npm/v/@veebisepad/vue-query-filters.svg)](https://www.npmjs.com/package/@veebisepad/vue-query-filters) [![license](https://img.shields.io/npm/l/@veebisepad/vue-query-filters.svg)](https://github.com/veebisepad/vue-query-filters/blob/main/LICENSE) Works seamlessly with Spatie [laravel-query-builder](https://spatie.be/docs/laravel-query-builder/v5/introduction) and [Inertia.js](https://inertiajs.com/) for filtering and sorting data in Laravel applications. ## Table of Contents - [Installation](#installation) - [Basic Usage](#basic-usage) - [API Reference](#api-reference) - [Core Functions](#core-functions) - [Configuration Options](#configuration-options) - [Filter Types](#filter-types) - [Filter Object Methods](#filter-object-methods) - [Examples](#examples) - [1. Basic Filter Setup and Usage](#1-basic-filter-setup-and-usage) - [2. Watching Filter Changes](#2-watching-filter-changes) - [3. Resetting Filters](#3-resetting-filters) - [4. Vue Component Example](#4-vue-component-example) - [5. Custom Filter Implementation](#5-custom-filter-implementation) - [6. Using with Laravel and Inertia.js](#6-using-with-laravel-and-inertiajs) - [TypeScript Support](#typescript-support) - [License](#license) ## Installation ```bash npm install @veebisepad/vue-query-filters ``` ## Basic Usage ```js import { useFilters, createFilterFactory } from '@veebisepad/vue-query-filters'; import { watch } from 'vue'; // Create filter factory const f = createFilterFactory(); // Define your filters const filters = useFilters( { category: f.single(), brands: f.multiple(), price: f.range(), }, { onApply: queryParams => { console.log('Filters changed:', queryParams); // Fetch data or update URL }, } ); ``` ## API Reference ### Core Functions | Function | Description | Parameters | Returns | |----------|-------------|------------|---------| | `createFilterFactory(options?)` | Creates a collection of filter factory functions | `options`: Configuration with optional `keyTransformer` function | Filter factory object | | `useFilters(filters, options?)` | Creates a reactive filter object | `filters`: Map of filter configurations<br>`options`: Optional configuration | Reactive filter object | ### Configuration Options #### `createFilterFactory` Options | Option | Type | Description | Default | |--------|------|-------------|---------| | `keyTransformer` | Function | Transforms filter keys for URL parameters | `key => key` | Example: ```js // For Laravel Spatie Query Builder format const f = createFilterFactory({ keyTransformer: key => `filter[${key}]` }); ``` #### `useFilters` Options | Option | Type | Description | Default | |--------|------|-------------|---------| | `delimiter` | String | Character used to separate multiple values | `','` | | `onApply` | Function | Callback function triggered when filters are applied via `get()` | | `preserveQueryOrder` | Boolean | Preserves URL query parameter order when generating query objects | `true` | |`location` | LocationLike | Specify custom location (for SSR) uses window.location by default if applicable | `widow.location` | Example: ```js const filters = useFilters( { /* filter definitions */ }, { delimiter: ';', onApply: queryParams => { // Called when filters.get() is invoked console.log('Applied filters:', queryParams); // Update URL, fetch data, etc. } } ); ``` ### Filter Types | Filter | Description | Default Value | Example | |--------|-------------|---------------|---------| | `single()` | Single value filter | `null` | `f.single('default')` | | `multiple()` | Array-based filter | `[]` | `f.multiple(['default'])` | | `range()` | Filter with from/to values | `{from: null, to: null}` | `f.range({from: 10, to: 50})` | | `custom()` | User-defined filter behavior | Based on implementation | See Custom Filter example | ### Filter Object Methods | Method | Description | Parameters | Returns | |--------|-------------|------------|---------| | `get()` | Triggers the onApply callback | None | void | | `toSearchParams()` | Converts filters to URLSearchParams | None | URLSearchParams object | | `toQueryObject(transformKeys?)` | Creates object with filter key-values | `transformKeys`: Boolean (default: true) | Object with filter parameters | | `toOrderedQueryObject(transformKeys?)` | Creates object with filter key-values, preserving URL parameter order | `transformKeys`: Boolean (default: true) | Object with ordered filter parameters | | `data()` | Returns plain object of filter values | None | Filter values object | | `has(filter, value)` | Checks if value exists in filter | `filter`: Filter key<br>`value`: Value to check | Boolean | | `clear(filterKey, shouldGet?)` | Resets filter(s) to default | `filterKey`: String/Array of keys<br>`shouldGet`: Boolean to trigger onApply | Void | | `clearAll()` | Resets all filters | None | Void | | `setOptions(newOptions)` | Updates filter options | `newOptions`: New options object | Void | ## Examples ### 1. Basic Filter Setup and Usage ```js const f = createFilterFactory(); const filters = useFilters({ search: f.single(''), category: f.single(null), brands: f.multiple([]) }); // Set filter values filters.search = 'laptop'; filters.category = 'electronics'; filters.brands = ['apple', 'samsung']; // Check if filter has value console.log(filters.has('brands', 'apple')); // true // Get all filter values as query parameters const queryParams = filters.get(); ``` ### 2. Watching Filter Changes ```js import { watch } from 'vue'; import { useDebounceFn } from '@vueuse/core'; // Option 1: Simple watcher watch( filters, () => filters.get(), // Trigger onApply callback { deep: true } ); // Option 2: Debounced watcher const debouncedApplyFilters = useDebounceFn(() => { filters.get(); }, 300); watch(filters, () => debouncedApplyFilters(), { deep: true }); ``` ### 3. Resetting Filters ```js // Reset a single filter filters.clear('category'); // Reset multiple filters filters.clear(['brands', 'price']); // Reset all filters filters.clearAll(); ``` ### 4. Vue Component Example ```vue <script setup> import { useFilters, createFilterFactory } from '@veebisepad/vue-query-filters'; const f = createFilterFactory(); const filters = useFilters({ search: f.single(''), categories: f.multiple([]), priceRange: f.range({ from: null, to: null }) }); function applyFilters() { filters.get(); } </script> <template> <div> <h2>Product Filters</h2> <!-- Single filter --> <input v-model="filters.search" type="text" placeholder="Search products..." /> <!-- Multiple filter --> <div> <label><input type="checkbox" value="electronics" v-model="filters.categories" /> Electronics</label> <label><input type="checkbox" value="clothing" v-model="filters.categories" /> Clothing</label> </div> <!-- Range filter --> <div> <input v-model.number="filters.priceRange.from" type="number" placeholder="Min" /> <input v-model.number="filters.priceRange.to" type="number" placeholder="Max" /> </div> <button @click="applyFilters">Apply Filters</button> <button @click="filters.clearAll()">Reset All</button> </div> </template> ``` ### 5. Custom Filter Implementation ```js import { createFilterFactory, useFilters } from '@veebisepad/vue-query-filters'; // 1) Create a filter factory const factory = createFilterFactory(); // 2) Define a custom filter const myCustomFilter = factory.custom({ defaultValue: 123, parseQueryParam(value, delimiter) { // Expected to parse 'enabled,value' from the incoming query string // and return the parsed filter value }, serializeQueryParam(currentValue, delimiter) { // Expected to generate a string for the URL query parameter // or return null if the filter is inactive }, hasValue(filterValue, candidate) { // Expected to determine if the current filter value // 'matches' a given candidate }, }); // 3) Implement the custom filter in useFilters const filters = useFilters( { specialSetting: myCustomFilter, }, { onApply(queryParams) { // Triggered when filters.get() is called console.log('Custom filter changed:', queryParams); }, } ); // 4) Use the custom filter filters.specialSetting = 234; filters.get(); // calls onApply with updated query params ``` ### 6. Using with Laravel and Inertia.js ```js import { useFilters, createFilterFactory } from '@veebisepad/vue-query-filters'; import { router } from '@inertiajs/vue3'; import { watch } from 'vue'; // Create filter factory with key transformer for Laravel Query Builder const f = createFilterFactory({ keyTransformer: key => `filter[${key}]` }); const filters = useFilters( { name: f.single(), category: f.multiple(), price: f.range(), sort: f.single('-created_at') }, { onApply: queryParams => { // Navigate with Inertia preserving state router.visit(route('products.index', queryParams), { preserveState: true, preserveScroll: true, only: ['products'] }); } } ); // Auto-apply filters when they change watch(filters, () => filters.get(), { deep: true }); ``` ## TypeScript Support ```typescript import { useFilters, createFilterFactory } from '@veebisepad/vue-query-filters'; import type { SingleFilter, MultipleFilter, RangeFilter } from '@veebisepad/vue-query-filters'; const f = createFilterFactory(); const filters = useFilters({ category: f.single<string>('all'), brands: f.multiple<string>([]), price: f.range<number>({ from: null, to: null }), }); ``` ## License MIT