Skip to main content

Grid Events and Callbacks

Keep dataset lifecycle behavior in FdcDataSet and visual interaction behavior in FdcGrid.

Cell pointer events

Use onCellTapDown for low-level pointer-down handling and onCellDoubleTap for semantic double-click or double-tap actions:

FdcGrid(
dataSet: customers,
onCellTapDown: (context) {
final position = context.globalPosition;
final column = context.column;
},
onCellDoubleTap: (context) {
openCustomerDetails(context.recordId);
},
)

Both callbacks receive FdcGridCellPointerContext, which exposes:

PropertyPurpose
dataSetDataset attached to the grid.
rowStable row context for the target row.
columnResolved column configuration.
rowIndexZero-based row index in the current view.
columnIndexZero-based column index in the current layout.
recordIdInternal dataset record identifier, when available.
valueCurrent cell value.
globalPositionPointer position in global coordinates.
localPositionPointer position relative to the target body cell.

These are notification callbacks. They do not return a decision to the pointer gesture pipeline.

Cell changes

FdcGrid(
dataSet: customers,
onCellChanged: (context) {
final field = context.fieldName;
final oldValue = context.oldValue;
final value = context.value;
},
)

onCellChanged reports an accepted local write. Backend persistence remains part of the dataset apply flow.

Focus transitions

The grid exposes row, column, and exact-cell enter/exit callbacks:

FdcGrid(
dataSet: customers,
onRowEnter: (context) {},
onRowExit: (context) {},
onColumnEnter: (context) {},
onColumnExit: (context) {},
onCellEnter: (context) {},
onCellExit: (context) {},
)

These are notifications, not navigation veto hooks. Validation and posting rules belong in dataset lifecycle events.

Edit permission gates

FdcGrid(
dataSet: customers,
canEditRow: (rowIndex, row) => !row.valueOf<bool>('locked'),
canEditColumn: (rowIndex, column, row) =>
column.fieldName != 'id',
)

Keep these predicates fast and side-effect free because edit traversal can evaluate them repeatedly.

Column value lifecycle

Use onValueChanging to transform or reject the pending value and onValueChanged to observe a successful write for that column.

FdcTextColumn<String>(
fieldName: 'state',
onValueChanging: (context) {
final value = context.newValue?.trim().toUpperCase();
if (value == null || value.length != 2) {
return context.cancel('Use a two-letter state code.');
}
return context.replaceValue(value);
},
onValueChanged: (context) {
debugPrint('State changed to ${context.value}');
},
)

Use the grid-level onCellChanged callback when one screen needs a central notification surface across multiple columns.