Listenable.merge combines any controllers into a single subscription point. One listener — all validation:final username = TextEditingController();
final agreed = ValueNotifier<bool>(false);
final focus = FocusNode();
final form = Listenable.merge([username, agreed, focus]);
form.addListener(_validate);
In
_validate — all rules in one place, cross-field logic included. Results go into two notifiers:formError.value = 'Username is required';
formValid.value = false;
Wrap only the submit button in
ValueListenableBuilder<bool> — nothing else rebuilds.Dispose in one pass:
[username, agreed, focus]
.whereType<ChangeNotifier>()
.forEach((c) => c.dispose());
Works with
TextEditingController, ValueNotifier<T>, FocusNode, AnimationController, and any ChangeNotifier.No packages, no new mental model.
Full article with a breakdown of all field types and a live DartPad example
#TipOfTheDay #Dart #Flutter #plugfox #form #state #managment