@gramex/filters v2.0.0
@gramex/filters
filters renders data as filters using <select> / <input> elements, or frameworks like
Bootstrap,
bootstrap-select,
etc.
Sample usage:
gramex.filters.render({
container: "form",
data: {
city: [
{ label: "London", value: "LON" },
{ label: "Oslo", value: "OSL" },
{ label: "Paris", value: "PAR" },
],
channel: [
{ label: "Direct", value: "DIR" },
{ label: "Indirect", value: "IND" },
],
},
});Installation
Run npm install @gramex/filters
To use filters on the browser, include the script in your HTML:
<script src="https://cdn.jsdelivr.net/npm/@gramex/filters/filters.min.js"></script>
<!-- OR src="node_modules/@gramex/filters/filters.min.js"></script -->
<script>
gramex.filters.render({...})
</script>For use with ES6 modules, use:
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js"
// OR { render } from "https://cdn.skypack.dev/@gramex/filters"
// OR { render } from "https://esm.sh/@gramex/filters"
render({...})
</script>Usage
<form id="basic-usage"></form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
render({
container: "form#basic-usage",
data: {
product: ["Alpha", "Beta", "Gamma"],
city: ["London", "Oslo", "Paris"],
channel: ["Direct", "Indirect"],
},
});
</script>This renders:

<form id="basic-usage">
<select name="product">
<option value="Alpha">Alpha</option>
<option value="Beta">Beta</option>
<option value="Gamma">Gamma</option>
</select>
<select name="city">
<option value="London">London</option>
<option value="Oslo">Oslo</option>
<option value="Paris">Paris</option>
</select>
<select name="channel">
<option value="Direct">Direct</option>
<option value="Indirect">Indirect</option>
</select>
</form>Options
container: CSS selector or Element into which filter is renderedtype: type of HTML to generate. Can beselect: renders<select>and<option>elements in a HTML formbs5: renders Bootstrap 5 dropdownsbootstrap-selectselect2selectize
data: object with filter data. Keys are the filter names. Values are arrays of filter values.- Filter values can be a string:
{"choice": ["X", "Y", "Z"]} - Filter values can be an object:
{"choice": [{label: "X", value: "x"}, {label: "Y", value: "y"}]} - Filter names (like
choice) map to field names (like<select name="choice">)
- Filter values can be a string:
url: a URL that returns thedataabove.- At least one of
dataorurlis required dataoverridesurl- If
urlis used,gramex.filters.render()returns a Promise that resolves to the JSON response ofurl
- At least one of
- field: filter-specific field attributes. Keys are the filter names. Values are field attribute scalars or functions
{"city": {"multiple": true}, "product": {"multiple": false}}makes thecityfilter a multiple-select, but notproduct{"city": {"class": "form-select"}}adds aclass="form-select"to thecityselect
- fields: common field attributes
{"multiple": true}makes all filters multiple-selects{"class": "form-select"}adds aclass="form-select"to all selects
- value: filter-specific value attributes. Keys are the filter names. Values are value attribute scalars or functions
{"city": {"class": "small"}}addsclass="small"to all options in thecityfilter
- values: common value attributes
{"class": "small"}addsclass="small"to all options in all filters
Depending on the type, field and value attributes are treated specially, as below.
type="select"
field/fields attributes:
name: sets<select name="${name}">. E.g.name: "city"value: currently selected value. Setsselectedattribute on matching items. E.g.value: "LON"label: sets<label>${label} ...</label>. E.g.label: "City"default: avalueobject to use as default, if it's missing invalues. E.g.default: "-"ordefault: {label: "All", value: ""}multiple: true: setsmultipleon<select>. E.g.multiple: truevalues: list of values to render as options. Defaults todata[name]selector: renders existing<select>elements if found. E.g.selector: "select[data-name="${name}]"renders matching<select data-name="...">if they exist, else creates new onesrender: function to render HTML if no<select>is found. Defaults roughly to({label, name}) => `<label>${label} <select name="${name}"></select></label>`;
value/values attributes:
value: sets<option value="${value}">label: sets<option>${label}</option>. Defaults tovaluerender: function to render HTML if no<option>is found. Defaults roughly to({label, value}) => `<option value="${value}">${label}</option>`;
type="bs5"
field/fields attributes:
name: sets<div class="dropdown ${name}">. E.g.name: "city"value: currently selected value. Setsclass="active"on matching items. E.g.value: "LON"label: sets<button>${label}</button>. Defaults toname. E.g.label: "City"multiple: TODO: not implemented yetdefault: avalueobject to use as default, if it's missing invaluesE.g.default: "-"ordefault: {label: "All", value: ""}buttonClass: sets<button class="dropdown-toggle ${buttonClass}">dropdownClass: sets<div class="dropdown ${dropdownClass}">menuClass: sets<ul class="dropdown-menu ${menuClass}"></ul>values: list of values to render as options. Defaults todata[name]selector: renders existing.dropdownelements if found.render: function to render HTML if no.dropdownis found
value/values attributes:
value: setsactiveclass on.dropdown-itemifvaluematches the current valuelabel: sets<li><a class="dropdown-item"}>${label}</a></li>. Defaults tovaluerender: function to render HTML if no<option>is found. Defaults roughly to({label}) => <li><a class="dropdown-item">${label}</a></li>
Examples
Fetch data from URL
This loads data from data-sales.json and renders it as filters into the <form>.
<form></form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
render({
container: "form",
url: "data-sales.json",
});
</script>Sample data-sales.json:
{
"product": ["Alpha", "Beta", "Gamma"],
"city": ["London", "Oslo", "Paris"],
"channel": ["Direct", "Indirect"]
}This renders:

Add classes to field
Add fields.class to specify classes for all fields:
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<form class="d-flex"></form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
render({
container: "form",
url: "data-sales.json",
fields: { class: "form-select me-2" },
});
</script>This renders:

Use existing HTML
To apply the filters to existing (styled) HTML, the <select> elements should have a name=,
class= or id= that matches the field name.
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<form class="row">
<div class="col"><select name="city" class="form-select"></select></div>
<div class="col"><select name="product" class="form-select"></select></div>
<div class="col"><select name="channel" class="form-select"></select></div>
</form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
render({
container: "form",
url: "data-sales.json",
});
</script>This re-uses the existing <select> elements in the same order and style as in the HTML:

Set selected values
Add fields.value to set selected values:
<form class="d-flex"></form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
render({
container: "form",
url: "data-sales.json",
fields: { value: { product: "Beta", city: "Oslo", channel: "Direct" } },
});
</script>This renders:

Set custom labels
Add value.[name].label to set custom labels:
<form></form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
const productDetails = {
Alpha: "Version Alpha: $100",
Beta: "Version Beta: $400",
Gamma: "Version Gamma: $1,000",
};
render({
container: "form",
url: "data-sales.json",
value: {
product: { label: ({ value }) => productDetails[value] },
},
});
</script>This renders:

Add default value
Add fields.default.[name] to add a default value:
<form></form>
<script type="module">
import { render } from "node_modules/@gramex/filters/filters.js";
render({
container: "form",
url: "data-sales.json",
fields: {
default: {
product: { label: "Any product", value: "" },
city: { label: "Any city", value: "" },
channel: { label: "Any channel", value: "" },
},
},
});
</script>This renders:
