2.7.0 (2026-05-06)
Non-breaking minor release. Headlined by a four-bundle correctness sweep across the directive lifecycle, path utilities, state-sync, and equality machinery, plus two new opt-in features for draft / auto-save workflows and dependent-field display tuning.
Compatibility: Angular
>=19, RxJS>=7.8.0, Vest>=5.4.6. No public-API removals; no behavior changes for forms not opting into the new features.
ngx-vest-forms
✨ New features
-
Field-blur events for draft workflows ([#0f86da4]) — adds
(fieldBlur)output andNgxFieldBlurEventtype onngxVestForm. Emits a fresh, validated snapshot of the blurred field's value plus full form value, designed for auto-save / draft-persistence flows that need to fire on blur rather than on every keystroke. Handles nested control paths, dynamic groups, radios, and repeated leaf names; cancels in-flight emissions on form reset.- New public exports:
NgxFieldBlurEventtype.
- New public exports:
-
Opt-in dependent-field validation display ([#a14b2ea], closes #93) — fields that are tracked by a
validationConfigdependency can now be configured to show errors only after they (or their dependency) have been touched. Avoids the surprise where dependent fields lit up on first render. Off by default; enable via the existing validation-config builder. -
Pluggable equality function ([#ea711c6]) — adds the
NGX_EQUALITY_FNinjection token (typed viaNgxEqualityFn). Lets consumers swap the form-value diff strategy (e.g. drop inlodash.isEqual, a structural-hash compare, or anything cheaper for known-shape models). Defaults preserve the existing semantics withObject.isshort-circuit on top-level identity.- New public exports:
NGX_EQUALITY_FN,NgxEqualityFn.
- New public exports:
-
Reactive
pendingDebounceinput ([#eb9d690]) —[pendingDebounce]onform-group-wrapperis now a signal-accessor input; runtime changes propagate. Previously read once at construction. Adds the publicDebouncedPendingStateOptionsInputtype.
Bug fixes — the four-bundle correctness sweep
Bundle A — Lifecycle safety ([#104] / #108)
- New internal
destroy-schedulerprimitive (scheduleTimeout/scheduleMicrotask) that ties timer / microtask cancellation toDestroyRef. form.directiveandvalidate-root-form.directivenow route async work through it. Result: no moreViewDestroyedErrorafter destroy-mid-async-validation, no leakedsetTimeouts, and nocdr.detectChanges()/updateValueAndValidity()writes against destroyed views.- Async validators now emit cleanly even when the directive is torn down before resolution.
Bundle B — Path utilities ([#105] / #109)
setValueAtPathno longer destroys arrays. CallingsetValueAtPath(form, 'addresses[0].street', 'x')on an existing populated array used to silently overwrite the entire array with{}, wiping every sibling entry. Bracket notation now decides container shape from the segment (numeric → array, string → object) and preserves siblings.parseFieldPathrejects malformed segments ('a..b','.a','a.','.[' patterns) with a dev-modeconsole.warninstead of silently truncating. Production builds are unchanged (warning isngDevMode-gated and tree-shakable).validateShapeis correct on opaque values.Date,Map,Set,RegExp,File,Blobshort-circuit recursion instead of being walked as plain records. Numeric-key detection switched fromparseFloatto^\d+$, so'123abc'is no longer silently mapped to array index0— it's flagged as a type mismatch (TYPE_MISMATCHwarning when the shape expects a primitive).
Bundle C — State-sync correctness ([#106] / #112)
- Empty form no longer shows ghost data.
formState().valuenow resets vialinkedSignalwhen all controls are dynamically removed, instead of returning the previous snapshot. ngxValidateRootFormModeprecedence matches the docstring. Default switched to anundefinedsentinel so the runtime can distinguish "not set" from'submit'. Order:ngx ?? legacy ?? 'submit'. Observable difference only when bothngx- and legacy attributes are set explicitly; existing single-attribute usage is unchanged.- Late-attached
NgModel.controlis retried viaafterNextRendersoform-control-statecorrectly tracks controls that haven't attached yet at construction time. - Touched state syncs for dependent validation ([#299a29d]) — blurring a field now propagates touched into dependents so their error display flips on the same tick.
- End-date validation now checks both endpoints exist before comparing, fixing a false-positive on partial date ranges ([#fcd88b6]).
Bundle D — Equality polish ([#107] / #110)
fastDeepEqualgot real cycle detection. A singleWeakMapof seen pairs replaces the previous depth-10 reference-fallback. Two distinct cyclic objects with identical structure now compare equal; self-referential objects compare equal to themselves; deep trees beyond 10 levels are correctly compared instead of bailing to reference equality and triggering spurious re-renders / breakingdistinctUntilChanged.- Functions are treated as reference-only.
- Existing
Map/Set/Date/RegExpsemantics preserved and pinned by tests.
🧹 Internal / refactors
cloneDeepis still exported but now logs adev-modedeprecation warning once. Scheduled for removal in v3 ([#114]). UsestructuredClone.field-clearingswitched toObject.hasOwn.mergeValuesAndRawValuesnow treatsnulltarget likeundefinedso disabled-control raw values aren't dropped from submit payloads.
Demo apps & examples (projects/examples)
These only affect the examples / docs site / Storybook.
- Auto-save on blur demo ([#7d6c106]) — end-to-end demo of the new
(fieldBlur)output for draft persistence, including dynamic groups and submit-time persistence policy. Documented indocs/AUTO-SAVE-ON-BLUR.md. - Composite custom-control adapter recipe ([#05e48c5]) — recipe demo showing how to wire one
ngModelvalue to multiple field paths with proper a11y. Documented indocs/COMPOSITE-ADAPTER-RECIPE.md. A first-class library API is tracked in #100.
Docs
- New:
docs/AUTO-SAVE-ON-BLUR.md,docs/COMPOSITE-ADAPTER-RECIPE.md,docs/VESTJS-SKILL.md. - Updated:
docs/API-TOKENS.md—NGX_EQUALITY_FNdocumented. - The bug-sweep PRD that drove Bundles A–D now lives at
docs/prd/PRD-bug-sweep.mdfor historical reference.