Define the data contract once, then bind the screen to it.
An FDC screen starts with field definitions and an FdcDataSet. The dataset owns records and cursor position, while grids and editors observe that shared state. There is no second form model to synchronise with the table.
Field metadata remains useful beyond rendering: type conversion, null handling, labels, validation, keys, defaults, lookup behaviour, filtering, and persistence all refer to the same definition.
final customers = FdcDataSet(
fields: const <FdcFieldDef>[
FdcIntegerField(name: 'id', isKey: true),
FdcStringField(name: 'name', required: true),
],
adapter: customerAdapter,
);
await customers.open();
DataSet
Records, cursor, edit state, validation, query state, and persistence meet in one explicit model.
Learn more →Fields
Typed metadata drives value access, editors, columns, validation, filters, and adapters.
Learn more →Data binding
Bind multiple controls to the same current record without duplicating application state.
Learn more →Editing is a state transition, not a loose callback.
Calling edit() creates an edit buffer. Bound controls write to that buffer. post() evaluates calculated values and validation before accepting the record; cancel() restores the previous values. Insert and delete follow the same deliberate lifecycle.
Callbacks such as beforePost, onFieldChanged, and onValidationError run at the dataset boundary, so the rule applies whether the operation began in a grid, a standalone editor, or application code.
customers.edit();
customers['name'] = 'BluePeak Logistics';
// post() calculates, validates, and accepts the edit.
// cancel() restores the original record instead.
customers.post();
CRUD operations
Use explicit insert, edit, post, cancel, and delete operations with predictable state changes.
Learn more →Lifecycle callbacks
Put business policy at supported veto, notification, and error points.
Learn more →Change tracking
Inspect pending updates and original values before persistence accepts them.
Learn more →The grid and form do not compete for ownership of the record.
An FdcGrid can present the full active view while an FdcTextEdit, date editor, combo, or custom control binds to a field on the current record. Cursor movement updates the editors; an editor change is immediately visible in the grid.
That shared workflow is the basis for compact lookup screens, dense operational grids, guided forms, and combinations of all three.
FdcGrid(
dataSet: customers,
columns: const [
FdcIntegerColumn(fieldName: 'id'),
FdcTextColumn(fieldName: 'name'),
],
)
FdcTextEdit(
dataSet: customers,
fieldName: 'name',
)
Structured grid editing
See how inplace cells participate in the same edit buffer and validation pipeline.
Learn more →Data-aware editors
Build focused record forms without introducing another state model.
Learn more →Adapters
Move from local rows to SQLite, JSON, REST, or a custom backend without replacing the UI workflow.
Learn more →Start with one dataset and one record lifecycle.
Install Flutter Data Components from pub.dev, define the first typed dataset, and connect it to a grid or data-aware editor.