Validation
Validation is part of the dataset post lifecycle. A record is validated before posted values become committed dataset state.
Required fields
The simplest rule belongs in schema metadata:
FdcStringField(
name: 'name',
label: 'Name',
required: true,
)
Required rules are enforced by built-in dataset validation.
Field-level validation
Use a field validator when a rule belongs to one field but may still need row context:
FdcStringField(
name: 'code',
label: 'Code',
validator: (row, value) {
final text = value as String?;
if (text != null && text.length < 3) {
return 'Code must contain at least 3 characters.';
}
return null;
},
)
Return null when the value is valid, or a user-facing message when it is invalid.
Record-level validation
Cross-field business rules belong in recordValidator:
final dataSet = FdcDataSet(
fields: fields,
recordValidator: (row) {
final start = row['start_date'] as DateTime?;
final end = row['end_date'] as DateTime?;
if (start != null && end != null && end.isBefore(start)) {
return [
const FdcValidationError(
message: 'End date must not be before start date.',
fieldName: 'end_date',
),
];
}
return const [];
},
);
A record validator returns zero or more FdcValidationError objects and can target a specific field or the record as a whole.
React to validation failures
Use onValidationError when the application needs to react to validation failures:
final dataSet = FdcDataSet(
fields: fields,
onValidationError: (dataSet, errors) {
// Display or route validation feedback as needed.
},
);
The dataset remains the validation authority whether edits originate from code, a data-aware editor, or the grid.
Keep rules near their owner
A practical rule of thumb:
- schema constraints such as required values belong on field definitions;
- one-field custom rules belong in the field validator;
- cross-field and whole-record rules belong in
recordValidator.
This keeps validation reusable across every UI bound to the dataset.