Skip to main content

Data operations

Sort, filter, paginate, aggregate. All run off the stateManager from onLoaded.

Sort, filter, paginate

sm.toggleSortColumn(column); // asc -> desc -> none
sm.sortByColumns([ // multi-column
(column: sm.columns[2], ascending: true),
(column: sm.columns[0], ascending: true),
]);
sm.sortByColumns([]); // clear

sm.setFilter((row) => // keep matching rows; source untouched
'${row.cells['name']?.value}'.toLowerCase().contains(query));
sm.setFilter(null); // clear

sm.setPageSize(15); sm.setPage(2); // paginate

Drop-in pager widget:

Column(children: [
Expanded(child: BCellGrid(columns: cols, rows: rows,
onLoaded: (e) => setState(() => _sm = e.stateManager))),
if (_sm != null) BCellPagination(_sm!),
]);

Aggregates

sm.sum('price'); sm.average('price');
sm.min('price'); sm.max('price'); sm.count('price');

Drop-in status bar (live Count / Sum / Average of the selection):

Column(children: [
Expanded(child: BCellGrid(columns: cols, rows: rows,
onLoaded: (e) => setState(() => _sm = e.stateManager))),
if (_sm != null) BCellAutoSum(_sm!),
]);

AutoFilter

Excel-style per-column filter dropdown (columns AND together). One controller drives every funnel button; or compose the predicate yourself.

final filter = BCellAutoFilter(sm);
BCellColumnFilterButton(controller: filter, column: someColumn);
filter.setAllowed('role', {'Engineer'}); filter.clear();

// Without the buttons:
sm.distinctValues('role'); // -> [Engineer, Admiral, ...]
sm.filterByValues({'role': {'Engineer'}});

Slicer

A chip bar of one column's distinct values; tapping chips filters the grid (chips within a column OR together, and it composes with filterByValues):

Column(children: [
BCellSlicer(sm, field: 'role'),
Expanded(child: BCellGrid(...)),
]);

Row grouping (outline)

Excel-style outline grouping over a run of displayed rows. The group's first row stays visible as its header and carries a +/− toggle in its first cell; collapsing hides the detail rows below it (they simply drop out of the display pipeline — filter → groups → paging).

final group = sm.groupRows(1, 3); // rows 1..3; row 1 = header
sm.toggleRowGroup(group!); // collapse / expand (the +/− tap)
sm.ungroupRows(group); // dissolve
sm.rowGroups; // current groups

Groups capture the row objects, so they survive sorting and filtering. Single-level groups only (no nesting, no column grouping); overlapping ranges are rejected (groupRows returns null).

Find & Replace, freeze rows

sm.replaceAll('ada', 'X'); // case-insensitive; skips formula/non-text cells
sm.setFrozenRowCount(2); // pin the top 2 rows below the header (freeze panes)