CxJS

Searching and Filtering

import { getSearchQueryPredicate } from 'cx/util'; Copied

Grids support client-side filtering using filterParams and onCreateFilter. This is ideal for filtering data already loaded in the browser.

<div controller={PageController}>
  <div className="flex gap-4 mb-4">
    <TextField value={m.search} icon="search" placeholder="Search..." />
    <LookupField
      value={m.cityFilter}
      options={m.cities}
      placeholder="Filter by city..."
      style="width: 200px"
    />
  </div>
  <Grid
    records={m.employees}
    columns={[
      { header: "Name", field: "fullName", sortable: true },
      { header: "Phone", field: "phone" },
      { header: "City", field: "city", sortable: true },
    ]}
    style="height: 300px"
    scrollable
    emptyText="No records match the filter criteria"
    filterParams={{ search: m.search, city: m.cityFilter }}
    onCreateFilter={(params: { search: string; city: string }) => {
      let { search, city } = params || {}
      let predicate = search ? getSearchQueryPredicate(search) : null
      return (record: Employee) => {
        if (city && record.city !== city) return false
        if (predicate) {
          return (
            predicate(record.fullName) ||
            predicate(record.phone) ||
            predicate(record.city)
          )
        }
        return true
      }
    }}
  />
</div>
Filter by city...
NamePhoneCity
Alice Johnson555-1234New York
Bob Smith555-2345Los Angeles
Carol White555-3456Chicago
David Brown555-4567Houston
Eva Green555-5678Phoenix
Frank Miller555-6789New York
Grace Lee555-7890Chicago
Henry Wilson555-8901Los Angeles

Type in the search field to filter records across all fields. Use the city dropdown to filter by a specific city. Both filters can be combined.

How It Works

The filterParams property holds the current filter state. It can be a single value or an object with multiple filter criteria. Whenever it changes, onCreateFilter is called to create a new predicate function:

<Grid
  records={m.employees}
  filterParams={{ search: m.search, city: m.cityFilter }}
  onCreateFilter={(params: { search: string; city: string }) => {
    let { search, city } = params || {};
    let predicate = search ? getSearchQueryPredicate(search) : null;
    return (record) => {
      if (city && record.city !== city) return false;
      if (predicate) {
        return (
          predicate(record.fullName) ||
          predicate(record.phone) ||
          predicate(record.city)
        );
      }
      return true;
    };
  }}
/>

The getSearchQueryPredicate utility creates a case-insensitive predicate that supports multiple search terms. Records pass the filter if any field matches all search terms.

Configuration

PropertyTypeDescription
filterParamsPropParameters passed to onCreateFilter when they change.
onCreateFilterfunctionCallback that receives filterParams and returns a predicate function (record) => boolean.
emptyTextstringText displayed when no records match the filter.