Skip to main content

Change Tracking

FdcDataSet tracks inserted, modified, and deleted records. This allows application code and adapters to work with changes rather than resending an entire dataset.

Record change states

A record can be:

StateMeaning
unchangedNo pending local change
insertedNewly inserted and not yet accepted
modifiedOne or more values differ from accepted values
deletedMarked for deletion

Normal application code rarely needs to manage these states directly. They are maintained by dataset edit operations.

Check for pending changes

if (dataSet.hasUpdates) {
// Persistent inserts, updates, or deletes are pending.
}

hasUpdates reflects persistent changes. An edit limited to non-persistent or calculated fields does not make the dataset report persistent updates.

Inspect the change set

changeSet returns a fresh immutable snapshot:

final changes = dataSet.changeSet;

print(changes.inserts.length);
print(changes.updates.length);
print(changes.deletes.length);

Each entry includes:

  • the dataset recordId used for result correlation;
  • current values;
  • originalValues;
  • changedFields.

For most applications, adapters and dataset APIs consume this model internally. Reading it directly is useful for review screens, diagnostics, audit previews, or custom workflow UI.

The three groups have different persistence meaning:

  • inserts contain new row values that do not yet exist in accepted storage state,
  • updates contain current values plus original accepted values and changed-field identity,
  • deletes retain enough original identity/value state for the adapter to delete the accepted storage row.

Key snapshots are especially important when an editable key field changes: storage targeting must use the original accepted key, while the current value can represent the new key state.

Persistent fields determine whether a change belongs in the persistence change set. Non-persistent/calculated fields can participate in UI state without creating storage updates by themselves.

Immediate updates are the default

The default update mode is:

FdcUpdateMode.immediate

With an adapter-backed dataset, post() and delete() commit the local operation and schedule persistence through the adapter.

Use dataset error and work callbacks to observe asynchronous persistence outcomes.

Cached updates

Choose cached updates when the user should make several changes and explicitly save or discard them as a group:

final dataSet = FdcDataSet(
fields: fields,
adapter: adapter,
updateMode: FdcUpdateMode.cachedUpdates,
);

Edit normally:

dataSet.edit();
dataSet['company'] = 'Northstar Systems';
dataSet.post();

dataSet.append();
dataSet['company'] = 'BluePeak Logistics';
dataSet.post();

Then apply all persistent changes:

final result = await dataSet.applyUpdates();

Cancel cached updates

dataSet.cancelUpdates();

cancelUpdates() reverts unapplied cached inserts, edits, and deletes and rebuilds the active view from accepted record state.

This operation is different from cancel():

  • cancel() discards the current active edit or insert buffer;
  • cancelUpdates() reverts all unapplied cached changes.

After apply succeeds or fails

On successful apply, the dataset accepts the persisted change set and reconciles any backend-confirmed values before returning to a clean accepted state. Generated keys and normalized server values therefore become part of the dataset's accepted row state.

On failed apply, pending tracked changes are not silently accepted. Structured adapter errors flow into the dataset error pipeline so the application can correct values or retry according to its workflow.

For cached updates, this distinction is critical: applyUpdates() is the persistence boundary, while prior post() calls only moved values from the active edit buffer into tracked pending changes.

Backend-confirmed values

When adapter apply succeeds, the dataset can merge backend-confirmed values into affected records. This matters for generated keys, server timestamps, normalized values, and other persistence-side results.

The adapter contract and apply result model are covered in the adapter documentation.

Persistence boundaries

A useful mental model is:

edit buffer
↓ post()
dataset tracked change
↓ applyUpdates() or immediate apply
adapter/storage

This separation allows the same editing UI model to support local data, immediate persistence, and explicit batch-save workflows.

Next: Data Binding