Build a CRUD screen
A typical FDC CRUD screen has one state owner—the dataset—and one or more data-aware views bound to it.
The core flow is:
load data → navigate → edit or insert → validate → post → apply changes
1. Define the schema
Start with field definitions that describe the business data, keys, labels, nullability, and validation rules.
final customers = FdcDataSet(
fields: const [
FdcIntegerField(name: 'customer_id', isKey: true),
FdcStringField(
name: 'company',
label: 'Company',
size: 120,
required: true,
),
FdcStringField(name: 'city', label: 'City', size: 80),
FdcStringField(name: 'state', label: 'State', size: 2),
],
);
See Fields for the schema/runtime field distinction.
2. Open or load the data
For local rows:
customers.loadRows([
{
'customer_id': 1,
'company': 'Northstar Trading',
'city': 'Boston',
'state': 'MA',
},
]);
For adapter-backed data:
await customers.open();
See Opening and Closing and Data Adapters.
3. Bind the grid
FdcGrid(
dataSet: customers,
columns: const [
FdcIntegerColumn(fieldName: 'customer_id', label: 'ID'),
FdcTextColumn(fieldName: 'company', label: 'Company'),
FdcTextColumn(fieldName: 'city', label: 'City'),
FdcTextColumn(fieldName: 'state', label: 'State'),
],
)
The grid edits the dataset's current record and edit buffer. You do not need a second copy of form state.
4. Edit, insert, and delete
customers.edit();
customers.fieldByName('company').value = 'Blue Ridge Supply';
await customers.post();
Insert:
customers.append();
customers.fieldByName('company').value = 'Lakeview Foods';
customers.fieldByName('city').value = 'Chicago';
customers.fieldByName('state').value = 'IL';
await customers.post();
Delete:
await customers.delete();
See CRUD Operations for the full lifecycle.
5. Validate before posting
Put simple constraints on field definitions and cross-field rules in recordValidator.
final customers = FdcDataSet(
fields: fields,
recordValidator: (row) {
final state = row['state'] as String?;
if (state != null && state.length != 2) {
return const [
FdcValidationError(
message: 'State must use a two-letter code.',
fieldName: 'state',
),
];
}
return const [];
},
);
See Validation.
6. Persist changes
With an adapter and immediate update mode, successful posts are applied through the adapter as part of the normal workflow.
For cached update workflows, stage several changes and apply them together:
await customers.applyUpdates();
See Change Tracking and Saving Changes.
Recommended screen structure
Keep the dataset in the screen state or in an application-level owner with a clear lifecycle. Bind grids and editors directly to it, and dispose the dataset when its owner is disposed.
That keeps navigation, validation, edit state, errors, and persistence coordinated through one model.