Editing an existing record
A form that opens blank and is submitted once needs almost none of this. A form that loads a record, is saved, reloads what the server actually stored and carries on being edited needs all of it: rebasing onto new data so "unsaved changes" means something, checking one answer without judging the whole form, reordering rows without walking them past each other, and reading a single field's state in one go.
State
Form dirty=False submits=0 validated=False valid=True
Customer touched=False dirty=False invalid=False messages=0
first error: —
Lines 0 total: €0.00 (loaded 0x)View source
// --- Rebasing onto what the server actually stored -----------------------------------------
// Reset() puts back the values the form was *constructed* with, which after a save are the wrong
// ones. Reset(values) writes the new ones and makes them the baseline, so IsFormDirty, an "unsaved
// changes" prompt and an undo button all mean what they say again. React Hook Form spells it
// reset(values).
state.Reset(new Dictionary<string, object?>
{
["Customer"] = stored.Customer,
["Lines[0].Description"] = stored.Lines[0].Description,
// ... every field the round-trip came back with
});
// --- Checking one answer, not the whole form -----------------------------------------------
// The path is enough; the schema resolves the definition. Returns false when nothing in the schema
// has that path, so a typo does not silently pass. React Hook Form spells it trigger(name).
await state.ValidateFieldAsync("Customer");
// --- Everything known about one field, in one read ------------------------------------------
var field = state.GetFieldState("Customer");
// field.IsTouched, field.IsDirty, field.IsInvalid, field.Error, field.Messages
// --- Saving a draft ---------------------------------------------------------------------------
// Snapshot() maps every path the schema binds to onto its value — including one entry per repeater
// row — and Reset(values) takes exactly that shape back. Together they are a complete
// save-and-restore: stash it in session storage while the user is halfway through, hand it back
// when they return.
var draft = state.Snapshot();
// … later …
state.Reset(draft);
// --- Repeater operations ---------------------------------------------------------------------
// Swap exchanges two rows and leaves every other row exactly where it was — which is what a
// drag-and-drop reorder means. Move shuffles everything in between along by one.
state.SwapArrayItems("Lines", 0, 1);
// Clear empties the list in one change, taking every row's messages and touched/dirty state with
// it, instead of costing a re-render and a re-index per row.
state.ClearArrayItems("Lines");
// --- One error at a time -----------------------------------------------------------------------
// A password that is too short, has no digit and has no symbol otherwise stacks three complaints
// under one box. Every rule still runs — this is about what the user reads, not what is checked.
state.SingleErrorPerField = true;
// --- Review mode ------------------------------------------------------------------------------
// A read-only wizard keeps Back and Next (reading a form is not editing it) and loses Submit and
// Reset.
state.ReadOnly = true;