@veebisepad/vue-query-filters
Version:
Reactive utility for managing URL query parameters in Vue 3.
329 lines (262 loc) • 10.2 kB
Markdown
# Vue Query Filters
A lightweight, flexible URL query parameter management system for Vue applications.
[](https://www.npmjs.com/package/@veebisepad/vue-query-filters)
[](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