ngx-vest-forms 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -16
- package/fesm2022/ngx-vest-forms.mjs +92 -33
- package/fesm2022/ngx-vest-forms.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ngx-vest-forms.d.ts +61 -17
package/README.md
CHANGED
|
@@ -116,7 +116,8 @@ That's all you need. The directive automatically creates controls, wires validat
|
|
|
116
116
|
- **Unidirectional state with signals** — Models are `NgxDeepPartial<T>` so values build up incrementally
|
|
117
117
|
- **Type-safe with runtime shape validation** — Automatic control creation and validation wiring (dev mode checks)
|
|
118
118
|
- **Vest.js validations** — Sync/async, conditional, composable patterns with `only(field)` optimization
|
|
119
|
-
- **Error display modes** — Control when errors show: `on-blur`, `on-submit`,
|
|
119
|
+
- **Error display modes** — Control when errors show: `on-blur`, `on-submit`, `on-blur-or-submit` (default), `on-dirty`, or `always`
|
|
120
|
+
- **Warning display modes** — Control when warnings show: `on-touch`, `on-validated-or-touch` (default), `on-dirty`, or `always`
|
|
120
121
|
- **Form state tracking** — Access touched, dirty, valid/invalid states for individual fields or entire form
|
|
121
122
|
- **Error display helpers** — `ngx-control-wrapper` component (recommended) plus directive building blocks for custom wrappers:
|
|
122
123
|
- `ngx-form-group-wrapper` component (recommended for `ngModelGroup` containers)
|
|
@@ -125,23 +126,60 @@ That's all you need. The directive automatically creates controls, wires validat
|
|
|
125
126
|
- **Cross-field dependencies** — `validationConfig` for field-to-field triggers, `ROOT_FORM` for form-level rules
|
|
126
127
|
- **Utilities** — Field paths, field clearing, validation config builder
|
|
127
128
|
|
|
128
|
-
### Error Display Modes
|
|
129
|
+
### Error & Warning Display Modes
|
|
129
130
|
|
|
130
|
-
Control when validation errors are shown to users with
|
|
131
|
+
Control when validation errors and warnings are shown to users with multiple built-in modes:
|
|
132
|
+
|
|
133
|
+
#### Error Display Modes
|
|
131
134
|
|
|
132
135
|
```typescript
|
|
133
136
|
// Global configuration via DI token
|
|
134
137
|
import { NGX_ERROR_DISPLAY_MODE_TOKEN } from 'ngx-vest-forms';
|
|
135
138
|
|
|
136
139
|
providers: [
|
|
137
|
-
{ provide: NGX_ERROR_DISPLAY_MODE_TOKEN, useValue: 'on-
|
|
140
|
+
{ provide: NGX_ERROR_DISPLAY_MODE_TOKEN, useValue: 'on-dirty' }
|
|
138
141
|
]
|
|
139
142
|
|
|
140
143
|
// Recommended: Use ngx-control-wrapper component
|
|
141
144
|
<ngx-control-wrapper [errorDisplayMode]="'on-blur'">
|
|
142
145
|
<input name="email" [ngModel]="formValue().email" />
|
|
143
146
|
</ngx-control-wrapper>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| Mode | Behavior |
|
|
150
|
+
| --------------------- | ---------------------------------------------------- |
|
|
151
|
+
| `'on-blur-or-submit'` | Show after blur OR form submit (default) |
|
|
152
|
+
| `'on-blur'` | Show only after blur/touch |
|
|
153
|
+
| `'on-submit'` | Show only after form submission |
|
|
154
|
+
| `'on-dirty'` | Show as soon as value changes (or after blur/submit) |
|
|
155
|
+
| `'always'` | Show immediately, even on pristine fields |
|
|
156
|
+
|
|
157
|
+
#### Warning Display Modes
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Global configuration via DI token
|
|
161
|
+
import { NGX_WARNING_DISPLAY_MODE_TOKEN } from 'ngx-vest-forms';
|
|
162
|
+
|
|
163
|
+
providers: [
|
|
164
|
+
{ provide: NGX_WARNING_DISPLAY_MODE_TOKEN, useValue: 'always' }
|
|
165
|
+
]
|
|
144
166
|
|
|
167
|
+
// Per-instance configuration
|
|
168
|
+
<ngx-control-wrapper [warningDisplayMode]="'on-dirty'">
|
|
169
|
+
<input name="username" [ngModel]="formValue().username" />
|
|
170
|
+
</ngx-control-wrapper>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
| Mode | Behavior |
|
|
174
|
+
| ------------------------- | ---------------------------------------------------- |
|
|
175
|
+
| `'on-validated-or-touch'` | Show after validation runs or touch (default) |
|
|
176
|
+
| `'on-touch'` | Show only after blur/touch |
|
|
177
|
+
| `'on-dirty'` | Show as soon as value changes (or after blur/submit) |
|
|
178
|
+
| `'always'` | Show immediately, even on pristine fields |
|
|
179
|
+
|
|
180
|
+
#### Group-Safe Mode Example
|
|
181
|
+
|
|
182
|
+
```html
|
|
145
183
|
// Group-safe mode (use this on an ngModelGroup container)
|
|
146
184
|
<ngx-form-group-wrapper ngModelGroup="address">
|
|
147
185
|
<ngx-control-wrapper>
|
|
@@ -175,14 +213,6 @@ For `ngModelGroup` containers, prefer using `<ngx-form-group-wrapper>` (group-sa
|
|
|
175
213
|
> **Styling note**: `ngx-control-wrapper` uses Tailwind CSS utility classes for default styling.
|
|
176
214
|
> If your project doesn't use Tailwind, see the [component docs](./projects/ngx-vest-forms/src/lib/components/control-wrapper/README.md#styling-dependency-tailwind-css) for alternatives.
|
|
177
215
|
|
|
178
|
-
**Available modes:**
|
|
179
|
-
|
|
180
|
-
- **`on-blur-or-submit`** (default) — Show errors after field is touched OR form is submitted
|
|
181
|
-
- **`on-blur`** — Show errors only after field loses focus (touched)
|
|
182
|
-
- **`on-submit`** — Show errors only after form submission
|
|
183
|
-
|
|
184
|
-
**Tip**: Use `on-blur-or-submit` for best UX — users get immediate feedback on touched fields while preventing overwhelming errors on pristine forms.
|
|
185
|
-
|
|
186
216
|
📖 **[Complete Guide: Custom Control Wrappers](./docs/CUSTOM-CONTROL-WRAPPERS.md)**
|
|
187
217
|
|
|
188
218
|
### Form State
|
|
@@ -212,14 +242,14 @@ Access complete form and field state through the `FormErrorDisplayDirective` or
|
|
|
212
242
|
- `isValid()` / `isInvalid()` — Validation state
|
|
213
243
|
- `isPending()` — Async validation in progress
|
|
214
244
|
- `errorMessages()` / `warningMessages()` — Current validation messages
|
|
215
|
-
- `shouldShowErrors()` — Computed based on display mode and state
|
|
245
|
+
- `shouldShowErrors()` / `shouldShowWarnings()` — Computed based on display mode and state
|
|
216
246
|
|
|
217
247
|
**Warnings behavior:**
|
|
218
248
|
|
|
219
249
|
- Warnings are **non-blocking** and do not make a field invalid.
|
|
220
|
-
-
|
|
221
|
-
-
|
|
222
|
-
-
|
|
250
|
+
- They are stored separately from `control.errors` and are cleared on `resetForm()`.
|
|
251
|
+
- These messages may appear after `validationConfig` triggers validation, even if the field was not touched yet.
|
|
252
|
+
- Use `NGX_WARNING_DISPLAY_MODE_TOKEN` to control when warnings display (see [Warning Display Modes](#warning-display-modes)).
|
|
223
253
|
|
|
224
254
|
**Tip**: For async validations, use `createDebouncedPendingState()` to prevent "Validating..." messages from flashing when validation completes quickly (< 200ms).
|
|
225
255
|
|
|
@@ -13,7 +13,12 @@ const SC_ERROR_DISPLAY_MODE_TOKEN = new InjectionToken('SC_ERROR_DISPLAY_MODE_TO
|
|
|
13
13
|
});
|
|
14
14
|
/**
|
|
15
15
|
* Injection token for configuring the default error display mode.
|
|
16
|
-
* Values:
|
|
16
|
+
* Values:
|
|
17
|
+
* - 'on-blur': Show errors after field is touched/blurred
|
|
18
|
+
* - 'on-submit': Show errors after form submission
|
|
19
|
+
* - 'on-blur-or-submit': Show errors after blur or form submission (default)
|
|
20
|
+
* - 'on-dirty': Show errors as soon as the field value changes
|
|
21
|
+
* - 'always': Show errors immediately, even on pristine fields
|
|
17
22
|
*/
|
|
18
23
|
const NGX_ERROR_DISPLAY_MODE_TOKEN = new InjectionToken('NGX_ERROR_DISPLAY_MODE_TOKEN', {
|
|
19
24
|
providedIn: 'root',
|
|
@@ -21,7 +26,11 @@ const NGX_ERROR_DISPLAY_MODE_TOKEN = new InjectionToken('NGX_ERROR_DISPLAY_MODE_
|
|
|
21
26
|
});
|
|
22
27
|
/**
|
|
23
28
|
* Injection token for configuring the default warning display mode.
|
|
24
|
-
* Values:
|
|
29
|
+
* Values:
|
|
30
|
+
* - 'on-touch': Show warnings after field is touched/blurred
|
|
31
|
+
* - 'on-validated-or-touch': Show warnings after validation runs or field is touched (default)
|
|
32
|
+
* - 'on-dirty': Show warnings as soon as the field value changes
|
|
33
|
+
* - 'always': Show warnings immediately, even on pristine fields
|
|
25
34
|
*/
|
|
26
35
|
const NGX_WARNING_DISPLAY_MODE_TOKEN = new InjectionToken('NGX_WARNING_DISPLAY_MODE_TOKEN', {
|
|
27
36
|
providedIn: 'root',
|
|
@@ -1966,6 +1975,7 @@ class FormErrorDisplayDirective {
|
|
|
1966
1975
|
this.shouldShowErrors = computed(() => {
|
|
1967
1976
|
const mode = this.errorDisplayMode();
|
|
1968
1977
|
const isTouched = this.isTouched();
|
|
1978
|
+
const isDirty = this.isDirty();
|
|
1969
1979
|
const isInvalid = this.isInvalid();
|
|
1970
1980
|
const hasErrors = this.errorMessages().length > 0;
|
|
1971
1981
|
const updateOn = this.updateOn();
|
|
@@ -1977,16 +1987,25 @@ class FormErrorDisplayDirective {
|
|
|
1977
1987
|
if (updateOn === 'submit') {
|
|
1978
1988
|
return !!(formSubmitted && hasErrorState);
|
|
1979
1989
|
}
|
|
1980
|
-
//
|
|
1981
|
-
|
|
1982
|
-
|
|
1990
|
+
// Handle the new display modes
|
|
1991
|
+
switch (mode) {
|
|
1992
|
+
case 'always':
|
|
1993
|
+
// Always show errors immediately, even on pristine fields
|
|
1994
|
+
return hasErrorState;
|
|
1995
|
+
case 'on-dirty':
|
|
1996
|
+
// Show when value has changed, OR when touched/submitted (for backwards compat)
|
|
1997
|
+
return !!(isDirty || isTouched || formSubmitted) && hasErrorState;
|
|
1998
|
+
case 'on-blur':
|
|
1999
|
+
// Show after touch (blur) or form submission (traditional behavior, not dirty-based)
|
|
2000
|
+
return !!(isTouched || formSubmitted) && hasErrorState;
|
|
2001
|
+
case 'on-submit':
|
|
2002
|
+
// Show only after form submission
|
|
2003
|
+
return !!(formSubmitted && hasErrorState);
|
|
2004
|
+
case 'on-blur-or-submit':
|
|
2005
|
+
default:
|
|
2006
|
+
// Show after blur (touch) OR submit (default behavior)
|
|
2007
|
+
return !!((isTouched || formSubmitted) && hasErrorState);
|
|
1983
2008
|
}
|
|
1984
|
-
// on-submit: show errors after submit
|
|
1985
|
-
if (mode === 'on-submit') {
|
|
1986
|
-
return !!(formSubmitted && hasErrorState);
|
|
1987
|
-
}
|
|
1988
|
-
// on-blur-or-submit: show errors after blur (touch) OR submit
|
|
1989
|
-
return !!((isTouched || formSubmitted) && hasErrorState);
|
|
1990
2009
|
}, ...(ngDevMode ? [{ debugName: "shouldShowErrors" }] : []));
|
|
1991
2010
|
/**
|
|
1992
2011
|
* Errors to display (filtered for pending state)
|
|
@@ -2017,6 +2036,47 @@ class FormErrorDisplayDirective {
|
|
|
2017
2036
|
}
|
|
2018
2037
|
return this.hasPendingValidation();
|
|
2019
2038
|
}, ...(ngDevMode ? [{ debugName: "isPending" }] : []));
|
|
2039
|
+
/**
|
|
2040
|
+
* Determines if warnings should be shown based on the specified display mode
|
|
2041
|
+
* and the control's state (touched/validated/dirty).
|
|
2042
|
+
*
|
|
2043
|
+
* NOTE: Unlike errors, warnings can exist on VALID fields (warnings-only scenario).
|
|
2044
|
+
* We don't require isInvalid() because Vest warn() tests don't affect field validity.
|
|
2045
|
+
*
|
|
2046
|
+
* UX Note: We include `hasBeenValidated` for `on-validated-or-touch` mode to support
|
|
2047
|
+
* cross-field validation. If Field A triggers validation on Field B (via validationConfig),
|
|
2048
|
+
* Field B should show warnings if it has them, even if the user hasn't touched Field B yet.
|
|
2049
|
+
* Unlike errors (which block submission), warnings are informational and safe to show.
|
|
2050
|
+
*/
|
|
2051
|
+
this.shouldShowWarnings = computed(() => {
|
|
2052
|
+
const mode = this.warningDisplayMode();
|
|
2053
|
+
const isTouched = this.isTouched();
|
|
2054
|
+
const isDirty = this.isDirty();
|
|
2055
|
+
const hasBeenValidated = this.hasBeenValidated();
|
|
2056
|
+
const hasWarnings = this.warningMessages().length > 0;
|
|
2057
|
+
const isPending = this.hasPendingValidation();
|
|
2058
|
+
const formSubmitted = this.formSubmitted();
|
|
2059
|
+
// No warnings to show or still pending
|
|
2060
|
+
if (!hasWarnings || isPending) {
|
|
2061
|
+
return false;
|
|
2062
|
+
}
|
|
2063
|
+
// Handle the warning display modes
|
|
2064
|
+
switch (mode) {
|
|
2065
|
+
case 'always':
|
|
2066
|
+
// Always show warnings immediately, even on pristine fields
|
|
2067
|
+
return true;
|
|
2068
|
+
case 'on-dirty':
|
|
2069
|
+
// Show when value has changed, OR when touched/submitted (for backwards compat)
|
|
2070
|
+
return isDirty || isTouched || formSubmitted;
|
|
2071
|
+
case 'on-touch':
|
|
2072
|
+
// Show after touch (blur) or form submission (traditional behavior, not dirty-based)
|
|
2073
|
+
return isTouched || formSubmitted;
|
|
2074
|
+
case 'on-validated-or-touch':
|
|
2075
|
+
default:
|
|
2076
|
+
// Show after validation runs or after touch/submit (default behavior)
|
|
2077
|
+
return hasBeenValidated || isTouched || formSubmitted;
|
|
2078
|
+
}
|
|
2079
|
+
}, ...(ngDevMode ? [{ debugName: "shouldShowWarnings" }] : []));
|
|
2020
2080
|
// Warn about problematic combinations of updateOn and errorDisplayMode
|
|
2021
2081
|
effect(() => {
|
|
2022
2082
|
const mode = this.errorDisplayMode();
|
|
@@ -2161,6 +2221,8 @@ let nextUniqueId$2 = 0;
|
|
|
2161
2221
|
* - `'on-blur-or-submit'` (default): Show errors after blur OR form submit
|
|
2162
2222
|
* - `'on-blur'`: Show errors only after blur
|
|
2163
2223
|
* - `'on-submit'`: Show errors only after form submit
|
|
2224
|
+
* - `'on-dirty'`: Show errors as soon as the field value changes
|
|
2225
|
+
* - `'always'`: Show errors immediately, even on pristine fields
|
|
2164
2226
|
*
|
|
2165
2227
|
* ```html
|
|
2166
2228
|
* <ngx-control-wrapper [errorDisplayMode]="'on-submit'">
|
|
@@ -2168,6 +2230,19 @@ let nextUniqueId$2 = 0;
|
|
|
2168
2230
|
* </ngx-control-wrapper>
|
|
2169
2231
|
* ```
|
|
2170
2232
|
*
|
|
2233
|
+
* ### Warning Display Modes
|
|
2234
|
+
* Control when warnings appear using the `warningDisplayMode` input:
|
|
2235
|
+
* - `'on-validated-or-touch'` (default): Show warnings after validation runs or touch
|
|
2236
|
+
* - `'on-touch'`: Show warnings only after touch/blur
|
|
2237
|
+
* - `'on-dirty'`: Show warnings as soon as the field value changes
|
|
2238
|
+
* - `'always'`: Show warnings immediately, even on pristine fields
|
|
2239
|
+
*
|
|
2240
|
+
* ```html
|
|
2241
|
+
* <ngx-control-wrapper [warningDisplayMode]="'on-dirty'">
|
|
2242
|
+
* <input name="email" [ngModel]="formValue().email" />
|
|
2243
|
+
* </ngx-control-wrapper>
|
|
2244
|
+
* ```
|
|
2245
|
+
*
|
|
2171
2246
|
* ### Accessibility Features (Automatic)
|
|
2172
2247
|
* - Unique IDs for error/warning/pending regions
|
|
2173
2248
|
* - `aria-describedby` linking errors to form controls
|
|
@@ -2200,9 +2275,9 @@ let nextUniqueId$2 = 0;
|
|
|
2200
2275
|
*
|
|
2201
2276
|
* Error & Warning Display Behavior:
|
|
2202
2277
|
* - The error display mode can be configured globally using the NGX_ERROR_DISPLAY_MODE_TOKEN injection token, or per instance using the `errorDisplayMode` input on FormErrorDisplayDirective (which this component uses as a hostDirective).
|
|
2203
|
-
* - Possible values: 'on-blur' | 'on-submit' | 'on-blur-or-submit' (default: 'on-blur-or-submit')
|
|
2278
|
+
* - Possible error display values: 'on-blur' | 'on-submit' | 'on-blur-or-submit' | 'on-dirty' | 'always' (default: 'on-blur-or-submit')
|
|
2204
2279
|
* - The warning display mode can be configured globally using NGX_WARNING_DISPLAY_MODE_TOKEN, or per instance using the `warningDisplayMode` input on FormErrorDisplayDirective.
|
|
2205
|
-
* - Possible values: 'on-touch' | 'on-validated-or-touch' (default: 'on-validated-or-touch')
|
|
2280
|
+
* - Possible warning display values: 'on-touch' | 'on-validated-or-touch' | 'on-dirty' | 'always' (default: 'on-validated-or-touch')
|
|
2206
2281
|
*
|
|
2207
2282
|
* Example (per instance):
|
|
2208
2283
|
* <div ngxControlWrapper>
|
|
@@ -2296,28 +2371,12 @@ class ControlWrapperComponent {
|
|
|
2296
2371
|
this.showPendingMessage = this.pendingState.showPendingMessage;
|
|
2297
2372
|
/**
|
|
2298
2373
|
* Whether to display warnings.
|
|
2299
|
-
*
|
|
2300
|
-
* 1. The field has been touched (user has interacted with it)
|
|
2301
|
-
* 2. The field has warnings to display
|
|
2302
|
-
* 3. The field is not currently pending validation
|
|
2303
|
-
*
|
|
2304
|
-
* NOTE: Unlike errors, warnings can exist on VALID fields (warnings-only scenario).
|
|
2305
|
-
* We don't require isInvalid() because Vest warn() tests don't affect field validity.
|
|
2374
|
+
* Delegates to FormErrorDisplayDirective's centralized shouldShowWarnings signal.
|
|
2306
2375
|
*
|
|
2307
|
-
*
|
|
2308
|
-
*
|
|
2309
|
-
* show warnings if it has them, even if the user hasn't touched Field B yet.
|
|
2310
|
-
* Unlike errors (which block submission), warnings are informational and safe to safe to show.
|
|
2376
|
+
* This ensures consistent warning display behavior across all form components
|
|
2377
|
+
* and supports the new 'on-dirty' and 'always' display modes.
|
|
2311
2378
|
*/
|
|
2312
|
-
this.shouldShowWarnings =
|
|
2313
|
-
const isTouched = this.errorDisplay.isTouched();
|
|
2314
|
-
const hasBeenValidated = this.errorDisplay.hasBeenValidated();
|
|
2315
|
-
const isPending = this.errorDisplay.isPending();
|
|
2316
|
-
const hasWarnings = this.errorDisplay.warnings().length > 0;
|
|
2317
|
-
const mode = this.errorDisplay.warningDisplayMode();
|
|
2318
|
-
const shouldShowAfterInteraction = mode === 'on-touch' ? isTouched : isTouched || hasBeenValidated;
|
|
2319
|
-
return shouldShowAfterInteraction && hasWarnings && !isPending;
|
|
2320
|
-
}, ...(ngDevMode ? [{ debugName: "shouldShowWarnings" }] : []));
|
|
2379
|
+
this.shouldShowWarnings = this.errorDisplay.shouldShowWarnings;
|
|
2321
2380
|
/**
|
|
2322
2381
|
* Computed signal that builds aria-describedby string based on visible regions
|
|
2323
2382
|
*/
|