ezy_form 1.0.0
ezy_form: ^1.0.0 copied to clipboard
Easy to handle form in Flutter without any complexity. Easy to use and customize.
1.0.0 (Unreleased) #
Breaking changes #
FormControl.reset()now restores the constructor-time initial value instead of clearing tonull. This brings it in line with the ecosystem (Angular reactive forms, web<form>.reset(), react-hook-form) and with theFormArrayControl.reset()snapshot behavior shipped in 0.0.2. Migration: if your code relied onreset()wiping a control tonull, call the newclear()instead.FormControlBaseinterface gainedclear(),markAsDisabled(),markAsEnabled(),enabled, anddisabledmembers. Any custom implementer of this interface must add them.FormControl.setValueis now a no-op when the new value equals the current value. No listeners are notified anddirty/touchedare not flipped. Most consumers won't notice this; if you relied onsetValueto forcibly retrigger a rebuild on an unchanged value, callnotifyListeners()directly or usemarkAsDirty()/markAsTouched().FormGroupnow requiresMap<String, FormNode>instead ofMap<String, Object>.FormControl,FormArrayControl, andFormGroupall implement the newFormNodeinterface, so existing code that passes form nodes compiles unchanged. Code that accidentally passed rawMap,int,String, etc. as map values will now fail at compile time instead of at runtime — this is the intended improvement.EzyFormControlbuilder signature changed from(BuildContext, FormControl<T>)to(BuildContext, FormControl<T>, TextEditingController, FocusNode). Migration: addcontroller, focusNodeparams (or_, __if unused).EzyFormControlis now aStatefulWidgetthat manages the controller/focus-node lifecycle internally.
New features #
-
FormControl.clear()— wipes the value tonulland clearsdirty/touched/error, regardless of the constructor's initial value. Use this for "Clear" buttons that should empty all fields. -
FormGroup.clear()— recursively clears every descendant control, preserving the group's structure (and any nested array shapes). -
FormArrayControl.clear()— keeps the current children but nulls every value, so an array with three slots stays at three empty slots. Composes naturally withFormGroup.clear(). -
FormArrayControl.removeAll()— drops every child outright, leavingcontrols = []. Use this when you want to start over from scratch (e.g. a "Remove all tags" button or rebuilding a dynamic form). -
FormControl.setValueacceptsmarkDirty: falsefor programmatic writes that should not flip thedirty/touchedflags (e.g. populating a form from an API response). -
FormControl.patchValue(T? v)— convenience wrapper aroundsetValue(v, markDirty: false). -
FormGroup.patchValue(Map)— recursively writes a (possibly partial) map of values into the group, descending into nestedFormGroups and dispatchingLists into nestedFormArrayControls. Unknown keys are ignored. Nothing is marked dirty. This is the one-liner replacement for "load form values from an API response". -
FormGroup.setValue(Map)— strict variant ofpatchValuethat throwsArgumentErroron missing or unknown keys, on shape mismatches (e.g. aListfor aFormGroupslot), and marks affected controls asdirty/touched. -
FormArrayControl.setValue(List<T?>)/patchValue(List<T?>)— resize the array's children list in place to match the new values. ExistingFormControlinstances are reused where possible, so widgets holding direct references stay valid. -
EzyFormControlnow provides aTextEditingControllerandFocusNodein its builder (breaking: builder signature changed from(context, control)to(context, control, controller, focusNode)). For text inputs, wire the controller and focus node to get automatic two-way sync including external writes fromreset,clear,patchValue, etc. For non-text inputs (checkbox, dropdown, slider, etc.) just ignore them (_, __). This replaces the previously-separateEzyTextBinding/EzyTypedTextBinding— one widget handles all cases. -
Optional
parse/formatcallbacks onEzyFormControlfor typed text binding. Supply them whenTis notString(e.g.int,double,DateTime). The binding never rewrites the user's raw text mid-keystroke: typing"abc"into an int field leaves"abc"visible while the model holdsnull. -
Optional
controller/focusNodeparameters onEzyFormControllet callers supply externally-owned instances for imperative access. -
Async validators —
FormControlnow acceptsasyncValidators, a list ofAsyncValidatorFn<T>(Future<String?> Function(T? value)). Callcontrol.validateAsync()orform.validateAsync()to run sync validators first, then async validators (in parallel across controls). While running,control.pendingistrueso the UI can show a spinner. Stale results are discarded when the value changes mid-flight.FormGroup.isPendingaggregates across all controls. -
FormControl.markAsDisabled()/markAsEnabled()— toggle theenabled/disabledstate on any control (FormControl,FormArrayControl,FormGroupArray). Disabled controls are skipped byvalidate(), excluded fromFormGroup.values, and always reportvalid = true. Constructors acceptenabled:(defaulttrue). Listeners are notified on state change so the UI can grey out fields. -
FormArrayControl.insert(index, [value])— insert a new child at any position. Out-of-range indices are clamped. -
FormArrayControl.move(from, to)— reorder children for drag-and-drop UX. PreservesFormControlidentity so widgets holding direct references stay valid. -
FormArrayControl.addControl(FormControl<T>)��� append a pre-built control without overwriting its validators, so individual items can have custom validation rules. -
FormGroup.addControl/removeControl/containsControl— dynamically add or remove controls at runtime. Supports dot-separated paths for nested groups. Useful for stepwise / wizard / dynamic forms where the set of fields changes based on user input. -
FormGroupArray— a new model for arrays ofFormGroups, designed for repeated structured sections like addresses, line items, or work history entries. ProvidesaddGroup()/removeGroup(index)/removeAll()/reset()/clear()/setValue(List<Map>)/patchValue(List<Map>). An optionaltemplateFactoryenablesaddGroup()without arguments and dynamic resizing viasetValue/patchValue. Array-level validators run viaGroupArrayValidatorFn. ImplementsFormNodeso it slots intoFormGroupmaps.FormGroup.groupArrayControl(name)provides lookup. -
EzyFormGroupArrayControl— widget for consuming aFormGroupArrayinside anEzyFormWidget, following the same pattern asEzyFormArrayControl. -
EzyFormControlWatcher<T>— a lightweight widget that watches a singleFormControland rebuilds when its value changes. Use it for reactive UI (e.g. conditionally showing a field when a checkbox is checked) without nesting inside the controlling field's builder. Accepts dotted paths for nested controls. -
EzyFormWatcher<R>— a selector-based widget that watches the entireFormGroupand rebuilds when any control changes. Aselectorfunction extracts the data you care about — use Dart records for type-safe multi-value watching. Also useful for derived/computed values likeform.isValid. -
Built-in validator library — new validators shipped alongside the existing
requiredValidator/requiredTrueValidator:emailValidator— permissive email pattern checkminLength(n)/maxLength(n)— String length boundsmin(n)/max(n)— numeric bounds (works withintanddouble)pattern(RegExp, {message})— regex match with optional custom errorequalTo(otherControl, {message})— cross-control equality (e.g. confirm password)compose([...])— runs all validators, returns first error (AND)composeOr([...])— returns null if any passes (OR), last error if all fail
All factory validators return
nullonnull/empty input so they compose cleanly withrequiredValidator— putrequiredValidatorfirst to enforce presence, then the shape/range validator after it.
Reset / clear / removeAll cheat sheet #
reset() |
clear() |
removeAll() |
|
|---|---|---|---|
FormControl<T> |
restore initial value | value → null |
— |
FormGroup |
recurse reset() |
recurse clear() |
— |
FormArrayControl<T> |
restore initial children | keep children, null values | drop every child |
FormGroupArray |
restore initial groups | keep groups, clear values | drop every group |
All three operations also clear dirty / touched / error and notify.
0.0.2 #
- Fix:
FormArrayControl.validate()now callsnotifyListeners()soEzyFormArrayControlwidgets rebuild to show errors after validation. - Fix:
FormArrayControl.markAsDirty()/markAsTouched()now callnotifyListeners(), matchingFormControl's behavior. - Fix:
FormArrayControl.validate()no longer silently treats a null or empty array as valid — the array's validators now run againstnullwhen there are no children, sorequiredValidatorcorrectly flags an empty array as invalid. - Fix:
FormGroup.isDirty/isTouchednow reflect edits made toFormControls nested inside aFormArrayControl(previously the parent group reportedfalsebecause only the array itself, not its children, was walked). - Fix:
FormArrayControl.remove(int index)is now a no-op when the index is out of range (orcontrolsis null), instead of throwingRangeError. - Fix: grammar in
FormGrouplookup error —"... not is invalid type"is now"... has invalid type". - Internal: removed a dead
List<T>branch inFormGroup._flattenMapValuesand a needless map copy in_travelNested. - Feat:
FormArrayControlnow acceptsarrayValidators: List<ArrayValidatorFn<T>>for rules that need the whole list (min/max length, uniqueness, etc.). The existingvalidatorsfield remains per-item and is propagated to each child. - Fix:
FormArrayControl.reset()now restores the array to its initial shape and values — items added viaadd()after construction are discarded and the original controls are rebuilt from a value snapshot taken in the constructor. Previously reset cleared each child in-place but left the list populated. - Fix (potentially breaking):
FormArrayControl.valuesnow returnsList<T?>?and includesnullentries for empty slots. An array with three empty items yields[null, null, null]rather than[], so the length matchescontrols.ArrayValidatorFn<T>'s argument type changed toList<T?>?accordingly. - Fix: removed
FormControl's deep-equality==/hashCodeoverride. Two distinct controls no longer compare equal just because they share the same value/state, which fixes silent collapse when storing controls in aSetorMapkey. - Fix: provider
of(context)helpers now throwStateErrorwith a descriptive message pointing atEzyFormWidget, instead of a plainException. - Chore: bumped
pubspec.yamlversion to0.0.2.
0.0.1 #
- TODO: Describe initial release.