Skip to main content

DataSet

FdcDataSet is the central object in the FD Components programming model. It owns a typed schema, records, cursor position, editing state, validation, change tracking, query state, and adapter interaction.

A grid or editor binds to the same dataset instead of maintaining a separate copy of business data. This gives application screens one consistent source of truth for navigation, editing, validation, and persistence.

Mental model

Think of a dataset as five cooperating layers:

  1. Schema — typed FdcFieldDef definitions describe field names, types, labels, validation, defaults, keys, and persistence metadata.
  2. Records — loaded rows are stored as dataset records and exposed through the active dataset view.
  3. Cursor — one visible record is current. Navigation changes that position and all bound controls follow it.
  4. Edit buffer — edits and inserts are staged through dataset state rather than written directly to accepted record values.
  5. Persistence boundary — local datasets can own rows directly; adapter-backed datasets load and apply data through an adapter.

Local and adapter-backed datasets

A local dataset owns rows directly:

final dataSet = FdcDataSet(
fields: const <FdcFieldDef>[
FdcIntegerField(name: 'id', isKey: true),
FdcStringField(name: 'name', required: true),
],
);

await dataSet.loadRows(<Map<String, Object?>>[
<String, Object?>{'id': 1, 'name': 'Northstar Analytics'},
]);

An adapter-backed dataset delegates loading and persistence:

final dataSet = FdcDataSet(
fields: customerFields,
adapter: adapter,
);

await dataSet.open();

The surrounding programming model remains consistent. Navigation, field access, editing, validation, grids, and editors continue to operate through the dataset.

The dataset owns lifecycle state

The main states are:

closed → loading → browse

edit / insert

browse

Adapter persistence may also enter applyingUpdates.

Use the state API when application behavior genuinely depends on lifecycle state:

if (dataSet.state == FdcDataSetState.edit) {
dataSet.post();
}

For common intent, prefer higher-level properties such as isOpen, isEmpty, and hasUpdates instead of building application logic around every state transition.

The dataset exposes classic cursor navigation:

dataSet.first();
dataSet.next();
dataSet.prior();
dataSet.last();
dataSet.moveToRecord(5); // 1-based public record number

The current record position is available through recordNumber, while recordCount reports the number of visible records in the active view.

print('${dataSet.recordNumber} / ${dataSet.recordCount}');

Filtering, sorting, searching, paging, and master-detail constraints can change the visible view without changing the core dataset programming model.

Read and write fields through the dataset

The shortest value access form is:

final name = dataSet['name'];

dataSet.edit();
dataSet['name'] = 'BluePeak Logistics';
dataSet.post();

For typed reads and metadata, use fieldByName and fieldDef:

final name = dataSet.fieldByName('name').asString;
final amountField = dataSet.fieldDef<FdcDecimalField>('amount');

print(amountField.precision);

The distinction between schema metadata and runtime values is covered in Fields.

UI components share the same dataset

A grid can bind to the full dataset:

FdcGrid(
dataSet: dataSet,
columns: const <FdcGridColumn>[
FdcIntegerColumn(fieldName: 'id'),
FdcTextColumn(fieldName: 'name'),
],
)

A data-aware editor binds to one field:

FdcTextEdit(
dataSet: dataSet,
fieldName: 'name',
)

Both observe the same current record and editing lifecycle. A change made through one bound component becomes visible to the others through dataset notifications.

What the DataSet is not

FdcDataSet is not only a collection of maps and it is not only a grid data source. It is the data workflow layer connecting:

  • typed field metadata;
  • records and cursor navigation;
  • editing and validation;
  • change tracking;
  • filtering, sorting, searching, and paging;
  • grids and editors;
  • data adapters and persistence.

That shared model is what allows FD Components screens to stay RAD-friendly as they grow beyond a single widget.

Next: Fields