Skip to main content

Filters - Vivid Component

Filters are a group of HoCs designed to handle the data-side of filtering & sorting. They have nothing to do with UI.

  • createEntityFilterer - simply factory to create your own high-level withFilteredEntityList, withFilteredQuery, etc.
  • withWhereaboutsFilter - basic query param powered filtering & sorting, powered by @rexlabs/whereabouts
  • withStatefulFilter - an alternative to Whereabouts filtering that simply uses local state
  • withFilter - a dumb building block used to parse filter configs & build controlled filters. This is low level & unlikely to be used in your app.

Simple Example​

@withWhereabouts()
@withWhereaboutsFilter(contactsFilter)
class RoutedFilters extends React.Component {
changeFilter = (e) => {
this.props.filters.setFilter({ id: 'name', value: e.target.value });
};

render() {
return (
<div>
<span>{this.props.filters.filterValues.name}</span>
<input type={'text'} onChange={this.changeFilter} />
</div>
);
}
}

Usage​

Filter Configs​

Filter configs are simply objects that contain 3 mandatory properties: namespace, sorting and filters.

sorting and filters are objects where each key represents a filterable (or sortable) field.

These field sub-objects can contain whatever extra data you want. Currently, only an optional initialValue field is used.

export default {
namespace: 'contacts',

// Sorting options
sorting: {
name: {
label: 'Name', // label does nothing, but it may be useful for your app!
initialValue: 'asc',
},

email: {
label: 'Email',
initialValue: 'asc',
},
},

// Filter options
filters: {
name: {
label: 'Name',
},
email: {
label: 'Email',
},
},
};

Props​

All filter HoCs pass down the following object, accessible via this.props.filters:

  • setFilters(filterObject): Shallow merges in new filter values (e.g. {name: 'Tom'})
  • setSorting(sortingObject): Shallow merges in new sorting values (e.g. {email: 'desc'})
  • set(filtersAndSorting): Shorthand function expects an object with keys filters and sorting
  • reset(): Restores filters and sorting to initial values
  • filterValues: Object of current filter values, keyed by filter field name as defined in config
  • sortingValues: Object of current sorting values, keyed by filter field name
  • config: The current filter config object being used

withWhereaboutsFilter(filterConfig, namespace, options)​

Basic query param filtering & sorting.

NOTE: This needs access to a whereabouts prop to work, so be sure to put it UNDER withWhereabouts()

  • filterConfig: The filter config object to use

  • namespace (optional): A custom namespace override. Used as query param prefixes. Defaults to namespace defined in your config.

  • options: Object of extra options:

    • sortingSeparator (default: |): String to split filter vlaues & sorting values in the url e.g. Chris|asc
    • urlSeparator (default: .): String to separate namespace & field names in query param keys e.g. contacts.email
    • onChange (optional): Function triggered on any filter/sorting change
    • initialValues (optional): Object to instantiate initial filter & sorting values
@withWhereabouts()
@withWhereaboutsFilter(contactsFilter)
class RoutedFilters extends React.Component {
changeFilter = (e) => {
this.props.filters.setFilter({ id: 'name', value: e.target.value });
};

render() {
return (
<div>
<span>{this.props.filters.filterValues.name}</span>
<input type={'text'} onChange={this.changeFilter} />
</div>
);
}
}

Tip: use onChange & initialValues to hook into the filters to do things like local storage persistence

withStatefulFilter(filterConfig, namespace, options)​

Exactly the same API as withWhereaboutsFilter, but uses React local state instead of query params.

  • filterConfig

  • namespace (optional)

  • options (optional)

    • onChange
    • initialValues
@withStatefulFilter(contactsFilter)
class LocalStateFilters extends React.Component {
changeFilter = (e) => {
this.props.filters.setFilter({ id: 'name', value: e.target.value });
};

render() {
return (
<div>
<span>{this.props.filters.filterValues.name}</span>
<input type={'text'} onChange={this.changeFilter} />
</div>
);
}
}

Tip: use onChange & initialValues to hook into the filters to do things like local storage persistence

createEntityFilterer(entityHoC, argsGetter)​

A higher order function that generates a the 'withFilteredEntity' HoC: an entity filterer to be used across your app.

Under the hood, it implements withWhereaboutsFilter.

  • entityHoC: The HoC from model generator to use.
  • argsGetter: Function that translates props into args. The args object is used by model generator. This function will likely need to be changed on a per-project basis, depending on how your backend API expects to receive filtering & sorting values. A sensible default is provided.

This function returns a HoC with the following params:

  • queryOrModel: Query or model to use (it supports either!)
  • filterConfig
  • options (optional):
    • urlSeparator
    • sortingSeparator
    • onChange
    • initialValues
import { withEntityList } from '@rexlabs/model-generator';
import { createEntityFilterer } from '@rexlabs/filters';
import contactsModel from './contacts-model';
import contactsFilter from './contacts-filter';

// You'd only want to do this once per app.
const withFilteredList = createEntityFilterer(withEntityList, (props) => ({
...props.filters.filterValues,
sort: props.filters.sortingValues,
}));

@withFilteredEntityList(contactsModel, contactsFilter)
class App extends React.Component {
filterEmail = () => {
this.props.filters.setFilters({ email: 'abc' });
};

render() {
console.log(this.props.contacts.list.items);
return <button onClick={this.filterEmail}>Filter Emails</button>;
}
}

Install dependencies

$ yarn

Available Commands

$ yarn start              # starts storybook, for visually testing filters
$ yarn test # runs all units tests
$ yarn test:watch # runs unit tests when files change
$ yarn build # bundles the package for production

Copyright © 2019 Rex Software All Rights Reserved.