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

Expression Filters

Learn how to create complex filter logic using LyteNyte Grid's expression capabilities.

Note

This guide assumes familiarity with LyteNyte Grid expressions and filtering concepts. The demos in this guide use the client row source to demonstrate expression filters.

For background, review the Client Row Filtering and Expressions Overview guide.

Creating Expression Filters

An expression filter returns a boolean value. LyteNyte Grid evaluates this expression against each row and keeps the row only if the result is true.

To make filter expressions easier to read and write, use column names rather than column IDs. For example, a user writes Gender == "Male" instead of row.customerGender == "Male".

Two mechanisms support this mapping:

  1. createResolvedIdentifierPlugin: Intercepts identifier nodes in the AST and rewrites them as function calls. This ensures Gender resolves from the context at evaluation time instead of being treated as a plain key.
  2. Context Object: Maps each column display name to a function that reads the column value from the current row using computeField.

The demo below preloads the expression Gender == "Male" && Quantity > 10. Type an expression to update the filter, or select one of the provided examples.

Filter Expressions

Fork code on stack blitzFork code on code sandbox

The demo includes the complete expression filter implementation. With only a few lines of code, expression filters let users create advanced filtering logic concisely.

Evaluator Setup

Start by creating an Evaluator instance. Instantiate the Evaluator either outside your React component or inside a useMemo hook to maintain a stable reference. Use standardPlugins and createResolvedIdentifierPlugin to enable advanced expression capabilities:

import {
createResolvedIdentifierPlugin,
Evaluator,
standardPlugins,
} from "@1771technologies/lytenyte-pro/expressions";
const evaluator = new Evaluator(
standardPlugins.concat([
createResolvedIdentifierPlugin({
identifiers: columns.map((x) => x.name ?? x.id),
args: ["row"],
}),
]),
);

Building the Filter Function

You can filter rows in LyteNyte Grid by passing a filter function. To implement an expression as a filter function, follow these steps:

  1. Create a context object that maps column names to functions that return the column value for a given row:

    import { computeField } from "@1771technologies/lytenyte-pro";
    import type { RowLeaf } from "@1771technologies/lytenyte-pro/types";
    const columnsContext = useMemo(
    () =>
    Object.fromEntries(
    columns.map((col) => [col.name ?? col.id, (row: RowLeaf) => computeField(col.field ?? col.id, row)]),
    ),
    [],
    );
  2. Pre-parse the expression into an AST to avoid tokenizing it on every predicate evaluation. Set undefinedIdentifierFallback to true to ensure partially typed expressions return true rather than throwing an error:

    const filter = useMemo(() => {
    if (!committed) return null;
    try {
    const ast = evaluator.ast(committed);
    return (row: RowLeaf<GridSpec["data"]>) =>
    !!evaluator.run(ast, { row, ...columnsContext }, { undefinedIdentifierFallback: true });
    } catch {
    return null; // invalid expression, show all rows
    }
    }, [committed, columnsContext]);
  3. Pass the filter function to useClientDataSource:

    const ds = useClientDataSource<GridSpec>({ data, filter });

Completion Provider Wiring

Pass a completion provider to ExpressionEditor.Root to enable autocomplete for column names. Use createCompletionProvider to create the default provider. Provide a Record<displayName, id> map so the provider does not require access to the full context object:

const provider = useMemo(
() => createCompletionProvider(Object.fromEntries(columns.map((col) => [col.name ?? col.id, col.id]))),
[],
);

Server-Side Expression Filters

The Evaluator can compute expression values on the client when all data referenced by the expression is available locally. If your data is stored on the server, serialize the expression AST and evaluate it server-side instead:

const ast = evaluator.ast(committed);
const serialized = JSON.stringify(ast); // send in your DataRequest

The AST is fully serializable as long as your plugins do not introduce custom node types that cannot be converted to JSON. standardPlugins and createResolvedIdentifierPlugin produce only serializable nodes.

Next Steps