LyteNyte Grid logo for light mode. Links back to the documentation home page.
Client Row Source

Client Row Having Filters

Having filters exclude group rows and their children after the grid performs grouping. Apply these filters to all groups or target specific depths.

Having filters run after the grid creates row groups. If a filter excludes a group row, the grid also removes all associated child rows.

This guide covers having filters in the client data source, not filter types. For client-side filtering, see the Filter Text guide.

Info

Having filters derives from the SQL HAVING clause, which filters grouped results after aggregation. For conceptual background, refer to the PostgreSQL HAVING guide.

Applying Having Filters

Having filters target aggregated group rows in the client data source. Review the Client Row Grouping and Client Row Aggregations guides for prerequisite knowledge.

To apply a having filter, set having on the client data source to an array of having filter functions (HavingFilterFn | null[ ]). The grid uses the function at each index to filter group rows at that depth. Use null to skip filtering at a depth.

The demo demonstrates a HavingFilterFn utilizing the filterModel provided by the grid API extension.

export interface GridSpec {
readonly data: BankData;
readonly column: { agg: string; allowedAggs: string[] };
readonly api: {
filterModel: PieceWritable<FilterModel>;
};
}

The filter model lets you build a filter representation before generating the filter function from it. The demo uses a custom floating header row component that allows users to modify the model’s value.

In the demo, the having filter applies to the second row grouping level: Education. For example, when you set the Balance filter to greater than $0, the grid removes the Secondary row from the Administration group and the Primary row from the Blue-Collar group.

Having Filter Function

Fork code on stack blitzFork code on code sandbox

The demo creates the HavingFilterFn function by iterating through the filters in the model and applying them one at a time.

const havingFilter = useMemo(() => {
const model = Object.entries(filterModel).filter(([, f]) => {
return f.kind && f.value && !Number.isNaN(Number.parseFloat(f.value));
});
if (!model.length) return;
const fn = (row: Grid.T.RowGroup) => {
for (const [key, f] of model) {
const value = row.data[key] as number;
const compare = Number.parseFloat(f.value!);
if (value == null || typeof value !== "number") return false;
if (f.kind === "eq" && value !== compare) return false;
else if (f.kind === "neq" && value === compare) return false;
else if (f.kind === "ge" && value < compare) return false;
else if (f.kind === "le" && value > compare) return false;
else if (f.kind === "lt" && value >= compare) return false;
else if (f.kind === "gt" && value <= compare) return false;
}
return true;
};
return [null, fn];
}, [filterModel]);

Next Steps