LyteNyte Grid logo for light mode. Links back to the documentation home page.
Filtering

Filtering Text

Create custom text filters in LyteNyte Grid. This guide covers common filters for string cell values.

Note

Applying a text filter varies depending on the row source. Refer to the guides below for each supported row data source:

While this guide focuses on using client row filtering, these filter concepts apply to all row sources.

Basic Text Filtering

LyteNyte Grid provides flexible filter capabilities that let you define any type of text filter. You can filter on contains, begins with, ends with, exact matching, or regex matching.

To create a text filter, define a function that receives a row node and returns true to keep the row or false to remove it.

For example, the following function filters a list of products and keeps only rows where the product name contains Xbox:

const filterXbox: Grid.T.FilterFn<GridSpec["data"]> = (row) => {
return row.data.product.includes("Xbox");
};

Click the Show Xbox Only switch to toggle the filter state.

Text Filtering

Fork code on stack blitzFork code on code sandbox

Filter Modifiers

Apply modifiers within the text filter function to control matching behavior. For example, convert values to lowercase to enable case-insensitive filtering:

const filterXbox: Grid.T.FilterFn<GridSpec["data"]> = (row) => {
return row.data.product.toLowerCase().includes("xbox");
};

Expand filter logic to ignore punctuation, trim whitespace, and normalize accented characters, such as mapping “á” to “a”:

const collator = new Intl.Collator(locale, { sensitivity: "case" });
const filterXbox: Grid.T.FilterFn<GridSpec["data"]> = (row) => {
const product = row.data.product.trim().replace(/[!"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]/g, "");
return collator.compare("xbox", product);
};

Text Filter Model

Define text filters dynamically rather than relying on predefined logic. LyteNyte Grid lets you define a filter model and a set of operations to build custom filters. This section presents one approach. Design the filter model that best fits your application’s requirements.

Begin by defining the type representation for your text filter. The code below defines a basic filter model you can use to create a filter function for the client row data source:

export type FilterStringOperator =
| "equals"
| "not_equals"
| "begins_with"
| "not_begins_with"
| "ends_with"
| "not_ends_with"
| "contains"
| "not_contains";
export interface FilterString {
readonly operator: FilterStringOperator;
readonly value: string;
}
export interface GridFilter {
readonly left: FilterString;
readonly right: FilterString | null;
readonly operator: "AND" | "OR";
}
export interface GridSpec {
readonly data: OrderData;
readonly api: {
readonly filterModel: PieceWritable<Record<string, GridFilter>>;
};
}

Open the filter popover by clicking the funnel icon on the Product, Customer, or Email columns.

Text Filter User Interface

Fork code on stack blitzFork code on code sandbox

The code below defines the filter model. It creates filter model state and passes it to the grid API as an extension. The demo also includes a filter UI for applying filters interactively.

When a user applies a filter, useMemo creates a new filterFn, which you then pass to the client data source. See the filter.tsx file in the demo’s expanded code for the logic that builds the filter UI.

const [filter, setFilter] = useState<Record<string, GridFilter>>({});
const filterModel = usePiece(filter, setFilter);
const filterFn = useMemo(() => {
const entries = Object.entries(filter);
const evaluateStringFilter = (operator: FilterStringOperator, compare: string, value: string) => {
if (operator === "equals") return value === compare;
if (operator === "begins_with") return compare.startsWith(value);
if (operator === "ends_with") return compare.endsWith(value);
if (operator === "contains") return compare.includes(value);
if (operator === "not_begins_with") return !compare.startsWith(value);
if (operator === "not_ends_with") return !compare.endsWith(value);
if (operator === "not_contains") return !compare.includes(value);
if (operator === "not_equals") return value !== compare;
return false;
};
return entries.map<Grid.T.FilterFn<GridSpec["data"]>>(([column, filter]) => {
return (row) => {
27 collapsed lines
const value = row.data[column as keyof GridSpec["data"]];
// This guide only covers string filters, so return false for non-string values.
if (typeof value !== "string") return false;
// Perform a case-insensitive match
const compareValue = value.toLowerCase();
const leftResult = evaluateStringFilter(
filter.left.operator,
compareValue,
filter.left.value.toLowerCase(),
);
if (!filter.right) return leftResult;
if (filter.operator === "OR") {
return (
leftResult ||
evaluateStringFilter(filter.right.operator, compareValue, filter.right.value.toLowerCase())
);
}
return (
leftResult &&
evaluateStringFilter(filter.right.operator, compareValue, filter.right.value.toLowerCase())
);
};
});
}, [filter]);

Next Steps