Attaching subforms
addSubform makes another form controller part of this one — its fields join validate, reset and every other broadcast. A dynamic list is the simplest case.
addSubform attaches another AdvancedFormController as a child. Its fields join the parent's validate,
resetAll, markReadOnly, clearErrors, setValidationMode, setValidationEnabled and every other broadcast, and
they count towards the parent's wasModified, canSubmit, validating and validationErrors.
class CheckoutFormController extends AdvancedFormController {
CheckoutFormController() {
registerFields([email]);
addSubform(shipping); // its fields are now part of this form
}
final email = AdvancedTextFieldController(validator: filled(MyError.required));
final shipping = ShippingFormController(); // another AdvancedFormController
}A dynamic list
Every guest below is its own AdvancedFormController, attached when added and detached when removed. The parent's
validate() walks every attached one.
Source2 files
final _emailPattern = RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$');
class GuestController extends AdvancedFormController {
GuestController() {
registerFields([name, email]);
}
final name = AdvancedTextFieldController(validator: filled('Name required'));
final email = AdvancedTextFieldController(
validator: (value) => _emailPattern.hasMatch(value) ? null : 'Not an email',
);
}
class GuestListController extends AdvancedFormController {
GuestListController() {
addGuest();
}
// Navigation state of our own: which subforms are on screen, in order.
// AdvancedFormState.subforms is a Set and knows nothing about order.
final guests = <GuestController>[];
void addGuest() {
final guest = GuestController();
addSubform(guest);
guests.add(guest);
notifyListeners();
}
void removeGuest(GuestController guest) {
// Detaches only. The parent still owns it and disposes it with itself.
removeSubform(guest);
guests.remove(guest);
notifyListeners();
}
}DocsActions, DocsSubmitButton and DocsTextField are shorthands these docs define, not part of the package. See Rendering fields for the widget code an app writes.Attaching, detaching, owning
addSubform(form)attaches. A no-op if already attached. The parent applies its validation mode to the subform at once — unless the subform has a mode of its own.removeSubform(form)detaches: the subform stops validating, notifying and counting towards the parent's state, and can be re-attached later. It does not dispose it.- The parent owns every subform it was ever given and disposes them all in its own
dispose(), attached or detached — the same way it owns registered fields. Do not dispose subforms yourself. - Ownership is single-parent. A subform attached to two parents is not supported.
- Calling
addSubformwith — or on — a disposed controller throws a descriptiveStateError. A disposed controller cannot be reused; build a fresh one per appearance.
Both membership changes recompute wasModified, so attaching an already-modified subform marks the parent modified at
once, and removing the only modified child clears the flag.