@fagon/ngx-intellitoolx 16.0.1 → 16.0.3
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 +663 -477
- package/esm2022/lib/form-validators/max-words.validator.mjs +2 -2
- package/esm2022/lib/form-validators/password-mismatch.validator.mjs +2 -2
- package/esm2022/lib/helpers/intellitoolx.helper.mjs +2 -2
- package/fesm2022/fagon-ngx-intellitoolx.mjs +4 -4
- package/fesm2022/fagon-ngx-intellitoolx.mjs.map +1 -1
- package/lib/form-validators/max-words.validator.d.ts +2 -2
- package/lib/form-validators/password-mismatch.validator.d.ts +1 -1
- package/lib/helpers/intellitoolx.helper.d.ts +1 -1
- package/package.json +16 -2
package/README.md
CHANGED
|
@@ -1,307 +1,386 @@
|
|
|
1
|
-
#
|
|
1
|
+
# IntelliToolx
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
IntelliToolx is a comprehensive Angular utility library designed to simplify reactive form development, validation, and user experience.
|
|
12
|
+
|
|
13
|
+
It provides powerful helpers, reusable validators, smart error handling, UI components, and developer-friendly utilities that eliminate repetitive boilerplate and enforce consistent form behavior across applications.
|
|
14
|
+
|
|
15
|
+
Built with scalability, accessibility, and maintainability in mind, IntelliToolx helps teams build robust, user-friendly form workflows faster and with fewer bugs.
|
|
5
16
|
|
|
6
17
|
### Installation
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
```bash
|
|
20
|
+
npm install intellitoolx
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
# IntelliToolxHelper
|
|
24
|
+
|
|
25
|
+
Utility helpers for working with Angular Reactive Forms, deep comparisons, change detection, and common data transformations.
|
|
26
|
+
Designed to simplify form state management, prevent accidental navigation, and normalize user input.
|
|
9
27
|
|
|
10
|
-
|
|
28
|
+
### Import
|
|
11
29
|
|
|
12
|
-
|
|
30
|
+
```ts
|
|
31
|
+
import { IntelliToolxHelper } from "intellitoolx";
|
|
32
|
+
```
|
|
13
33
|
|
|
14
|
-
Methods
|
|
34
|
+
## Methods
|
|
15
35
|
|
|
16
|
-
|
|
36
|
+
### captureInitialFormValue(form)
|
|
17
37
|
|
|
18
38
|
Captures and clones the initial value of a form and marks it as pristine.
|
|
19
39
|
|
|
20
|
-
|
|
40
|
+
```ts
|
|
41
|
+
static captureInitialFormValue(form: AbstractControl): any
|
|
42
|
+
```
|
|
21
43
|
|
|
22
44
|
Features
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
45
|
+
|
|
46
|
+
- Uses getRawValue() when available
|
|
47
|
+
- Marks form as pristine
|
|
48
|
+
- Returns a deep clone of the initial value
|
|
26
49
|
|
|
27
50
|
Example
|
|
28
|
-
const initial = IntelliToolxHelper.captureInitialValue(this.form);
|
|
29
51
|
|
|
30
|
-
|
|
52
|
+
```ts
|
|
53
|
+
const initial = IntelliToolxHelper.captureInitialFormValue(this.form);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### trimFormGroup(control)
|
|
31
57
|
|
|
32
58
|
Recursively trims whitespace from all string values in a form.
|
|
33
59
|
|
|
60
|
+
```ts
|
|
34
61
|
static trimFormGroup(control: AbstractControl): void
|
|
62
|
+
```
|
|
35
63
|
|
|
36
64
|
Supports
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
|
|
66
|
+
- FormGroup
|
|
67
|
+
- FormArray
|
|
68
|
+
- FormControl
|
|
40
69
|
|
|
41
70
|
Example
|
|
71
|
+
|
|
72
|
+
```ts
|
|
42
73
|
IntelliToolxHelper.trimFormGroup(this.form);
|
|
74
|
+
```
|
|
43
75
|
|
|
44
|
-
|
|
76
|
+
### deepEqual(obj1, obj2)
|
|
45
77
|
|
|
46
78
|
Performs a deep comparison between two values.
|
|
47
79
|
|
|
80
|
+
```ts
|
|
48
81
|
static deepEqual(obj1: any, obj2: any): boolean
|
|
82
|
+
```
|
|
49
83
|
|
|
50
84
|
Special behavior
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
85
|
+
|
|
86
|
+
- Treats null, undefined, and "" as equal
|
|
87
|
+
- Normalizes numeric comparisons
|
|
88
|
+
- Compares File objects by metadata
|
|
89
|
+
- Supports nested objects & arrays
|
|
55
90
|
|
|
56
91
|
Example
|
|
92
|
+
|
|
93
|
+
```ts
|
|
57
94
|
IntelliToolxHelper.deepEqual(a, b);
|
|
95
|
+
```
|
|
58
96
|
|
|
59
|
-
|
|
97
|
+
### isEmpty(value)
|
|
60
98
|
|
|
61
99
|
Checks if a value is empty.
|
|
62
100
|
|
|
101
|
+
```ts
|
|
63
102
|
static isEmpty(value: any): boolean
|
|
103
|
+
```
|
|
64
104
|
|
|
65
|
-
Returns true for:
|
|
66
|
-
null
|
|
67
|
-
undefined
|
|
68
|
-
empty string
|
|
69
|
-
whitespace-only string
|
|
105
|
+
Returns true for: `null, undefined, empty string, whitespace-only string `
|
|
70
106
|
|
|
71
|
-
|
|
107
|
+
### clone(value)
|
|
72
108
|
|
|
73
109
|
Creates a deep clone.
|
|
74
110
|
|
|
111
|
+
```ts
|
|
75
112
|
static clone(value: any): any
|
|
113
|
+
```
|
|
76
114
|
|
|
77
115
|
Uses structuredClone (Angular 14+ compatible).
|
|
78
116
|
|
|
79
|
-
|
|
117
|
+
### formHasChanges(initialValue, form)
|
|
80
118
|
|
|
81
119
|
Determines whether a form value has changed.
|
|
82
120
|
|
|
121
|
+
```ts
|
|
83
122
|
static formHasChanges(initialValue: any, form: AbstractControl): boolean
|
|
123
|
+
```
|
|
84
124
|
|
|
85
125
|
Example
|
|
126
|
+
|
|
127
|
+
```ts
|
|
86
128
|
if (IntelliToolxHelper.formHasChanges(initial, this.form)) {
|
|
87
|
-
// prompt user
|
|
129
|
+
// prompt user
|
|
88
130
|
}
|
|
131
|
+
```
|
|
89
132
|
|
|
90
|
-
|
|
133
|
+
### confirmIfChanged(hasChanges, confirmHandler?)
|
|
91
134
|
|
|
92
135
|
Shows confirmation if changes exist.
|
|
93
136
|
|
|
94
|
-
|
|
95
|
-
hasChanges: boolean,
|
|
96
|
-
|
|
97
|
-
): Promise<boolean>
|
|
137
|
+
```ts
|
|
138
|
+
static confirmIfChanged(hasChanges: boolean, confirmHandler?: ConfirmHandler): Promise<boolean>
|
|
139
|
+
```
|
|
98
140
|
|
|
99
141
|
Behavior
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
142
|
+
|
|
143
|
+
- Returns true if no changes
|
|
144
|
+
- Uses provided handler if available
|
|
145
|
+
- Falls back to browser confirm()
|
|
103
146
|
|
|
104
147
|
Example
|
|
105
|
-
const canLeave = await IntelliToolxHelper.confirmIfChanged(
|
|
106
|
-
hasChanges,
|
|
107
|
-
() => dialog.confirm()
|
|
108
|
-
);
|
|
109
148
|
|
|
110
|
-
|
|
149
|
+
```ts
|
|
150
|
+
const canLeave = await IntelliToolxHelper.confirmIfChanged(hasChanges, () => dialog.confirm());
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### registerBeforeUnload(shouldBlock, message?)
|
|
111
154
|
|
|
112
155
|
Prevents accidental page exit when changes exist.
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
shouldBlock: () => boolean,
|
|
116
|
-
|
|
117
|
-
): () => void
|
|
157
|
+
```ts
|
|
158
|
+
static registerBeforeUnload(shouldBlock: () => boolean, message?: string): () => void
|
|
159
|
+
```
|
|
118
160
|
|
|
119
|
-
Returns
|
|
120
|
-
Cleanup function to remove the listener.
|
|
161
|
+
Returns `Cleanup function to remove the listener.`
|
|
121
162
|
|
|
122
163
|
Example
|
|
123
|
-
const cleanup = IntelliToolxHelper.registerBeforeUnload(() =>
|
|
124
|
-
this.form.dirty
|
|
125
|
-
);
|
|
126
164
|
|
|
165
|
+
```ts
|
|
166
|
+
const cleanup = IntelliToolxHelper.registerBeforeUnload(() => this.form.dirty);
|
|
127
167
|
// later
|
|
128
168
|
cleanup();
|
|
169
|
+
```
|
|
129
170
|
|
|
130
|
-
|
|
171
|
+
### getFormControl(form, path)
|
|
131
172
|
|
|
132
173
|
Retrieves a nested FormControl using dot notation.
|
|
133
174
|
|
|
134
|
-
|
|
135
|
-
form: AbstractControl,
|
|
136
|
-
|
|
137
|
-
): FormControl<T> | null
|
|
175
|
+
```ts
|
|
176
|
+
static getFormControl<T>(form: AbstractControl, path: string): FormControl<T> | null
|
|
177
|
+
```
|
|
138
178
|
|
|
139
179
|
Supports
|
|
140
|
-
|
|
141
|
-
|
|
180
|
+
|
|
181
|
+
- Nested FormGroups
|
|
182
|
+
- FormArrays using numeric indexes
|
|
142
183
|
|
|
143
184
|
Example
|
|
144
|
-
const control = IntelliToolxHelper.getFormControl(this.form, 'address.street');
|
|
145
|
-
const item = IntelliToolxHelper.getFormControl(this.form, 'items.0.name');
|
|
146
185
|
|
|
147
|
-
|
|
186
|
+
```ts
|
|
187
|
+
const control = IntelliToolxHelper.getFormControl(this.form, "address.street");
|
|
188
|
+
const item = IntelliToolxHelper.getFormControl(this.form, "items.0.name");
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### convertImageToBase64(file)
|
|
148
192
|
|
|
149
193
|
Converts an image file to a Base64 string.
|
|
150
194
|
|
|
195
|
+
```ts
|
|
151
196
|
static convertImageToBase64(file: File): Promise<string>
|
|
197
|
+
```
|
|
152
198
|
|
|
153
199
|
Example
|
|
200
|
+
|
|
201
|
+
```ts
|
|
154
202
|
const base64 = await IntelliToolxHelper.convertImageToBase64(file);
|
|
203
|
+
```
|
|
155
204
|
|
|
156
|
-
|
|
205
|
+
### replaceCharacter(text, replaceChar, replaceWithChar)
|
|
157
206
|
|
|
158
207
|
Replaces all occurrences of a character in a string.
|
|
159
208
|
|
|
160
|
-
|
|
161
|
-
text: any,
|
|
162
|
-
|
|
163
|
-
replaceWithChar: string
|
|
164
|
-
): string
|
|
209
|
+
```ts
|
|
210
|
+
static replaceCharacter(text: any, replaceChar: string, replaceWithChar: string): string
|
|
211
|
+
```
|
|
165
212
|
|
|
166
213
|
Example
|
|
167
|
-
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
IntelliToolxHelper.replaceCharacter("1-2-3", "-", ":");
|
|
168
217
|
// 1:2:3
|
|
218
|
+
```
|
|
169
219
|
|
|
170
|
-
|
|
220
|
+
### convertJsonStringToJson(value)
|
|
171
221
|
|
|
172
222
|
Safely converts a JSON string into an object.
|
|
173
223
|
|
|
174
|
-
|
|
175
|
-
value: T | string | null | undefined
|
|
176
|
-
|
|
224
|
+
```ts
|
|
225
|
+
static convertJsonStringToJson<T>(value: T | string | null | undefined): T | null
|
|
226
|
+
```
|
|
177
227
|
|
|
178
228
|
Behavior
|
|
179
|
-
|
|
180
|
-
Returns
|
|
181
|
-
Returns
|
|
229
|
+
|
|
230
|
+
- Returns parsed object if valid JSON string
|
|
231
|
+
- Returns original object if already parsed
|
|
232
|
+
- Returns null if parsing fails
|
|
182
233
|
|
|
183
234
|
Example
|
|
235
|
+
|
|
236
|
+
```ts
|
|
184
237
|
const data = IntelliToolxHelper.convertJsonStringToJson<MyType>(jsonString);
|
|
238
|
+
```
|
|
185
239
|
|
|
186
|
-
|
|
240
|
+
Usage Pattern (Recommended)
|
|
187
241
|
|
|
188
|
-
|
|
242
|
+
```ts
|
|
243
|
+
initialValue = IntelliToolxHelper.captureInitialFormValue(this.form);
|
|
189
244
|
|
|
190
245
|
save() {
|
|
191
|
-
IntelliToolxHelper.trimFormGroup(this.form);
|
|
192
|
-
|
|
193
|
-
if (!IntelliToolxHelper.formHasChanges(this.initialValue, this.form)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
246
|
+
IntelliToolxHelper.trimFormGroup(this.form);
|
|
196
247
|
|
|
197
|
-
|
|
248
|
+
if (!IntelliToolxHelper.formHasChanges(this.initialValue, this.form)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// proceed with save
|
|
198
252
|
}
|
|
253
|
+
```
|
|
199
254
|
|
|
200
255
|
# IntellitoolxRegExps
|
|
201
256
|
|
|
202
257
|
A collection of commonly used regular expressions for validation in Angular and TypeScript applications.
|
|
203
258
|
|
|
204
|
-
Designed for:
|
|
205
|
-
Reactive Forms validation
|
|
206
|
-
Input sanitization
|
|
207
|
-
Reusable validation patterns
|
|
208
|
-
Consistent form behavior across projects
|
|
259
|
+
1. Designed for:
|
|
260
|
+
2. Reactive Forms validation
|
|
261
|
+
3. Input sanitization
|
|
262
|
+
4. Reusable validation patterns
|
|
263
|
+
5. Consistent form behavior across projects
|
|
209
264
|
|
|
210
|
-
Import
|
|
211
|
-
|
|
265
|
+
### Import
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { IntellitoolxRegExps } from "intellitoolx";
|
|
269
|
+
```
|
|
212
270
|
|
|
213
|
-
Available Regular Expressions
|
|
271
|
+
## Available Regular Expressions
|
|
214
272
|
|
|
215
|
-
|
|
273
|
+
### EMAIL_REGEX
|
|
216
274
|
|
|
217
|
-
EMAIL*REGEX: /^(?=.{1,50}$)[a-zA-Z0-9.*%+-]+@[a-zA-Z0-9.-]+\.[A-Za-z]{2,}
|
|
275
|
+
`EMAIL*REGEX: /^(?=.{1,50}$)[a-zA-Z0-9.*%+-]+@[a-zA-Z0-9.-]+\.[A-Za-z]{2,}$/`
|
|
218
276
|
|
|
219
277
|
Validates an email address with:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
278
|
+
|
|
279
|
+
1. Maximum length of 50 characters
|
|
280
|
+
2. Standard email format
|
|
281
|
+
3. Requires valid domain suffix (min 2 characters)
|
|
223
282
|
|
|
224
283
|
Valid Examples
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
284
|
+
|
|
285
|
+
- test@example.com
|
|
286
|
+
- user.name@mail-domain.org
|
|
287
|
+
- info123@test.co
|
|
228
288
|
|
|
229
289
|
Invalid Examples
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
@
|
|
290
|
+
|
|
291
|
+
- invalid-email
|
|
292
|
+
- user@
|
|
293
|
+
- @test.com
|
|
233
294
|
|
|
234
295
|
Usage (Angular Validator)
|
|
235
296
|
|
|
297
|
+
```ts
|
|
236
298
|
this.form = new FormGroup({
|
|
237
|
-
email: new FormControl(
|
|
238
|
-
Validators.pattern(IntellitoolxRegExps.EMAIL_REGEX),
|
|
239
|
-
]),
|
|
299
|
+
email: new FormControl("", [Validators.pattern(IntellitoolxRegExps.EMAIL_REGEX)]),
|
|
240
300
|
});
|
|
301
|
+
```
|
|
241
302
|
|
|
242
|
-
|
|
303
|
+
### NUMBER_REGEX
|
|
243
304
|
|
|
244
|
-
NUMBER_REGEX: /^\d
|
|
305
|
+
`NUMBER_REGEX: /^\d+$/`
|
|
245
306
|
|
|
246
307
|
Validates:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
No
|
|
250
|
-
No
|
|
308
|
+
|
|
309
|
+
- Whole numbers only
|
|
310
|
+
- No decimals
|
|
311
|
+
- No negative values
|
|
312
|
+
- No spaces or characters
|
|
251
313
|
|
|
252
314
|
Valid Examples
|
|
253
|
-
|
|
315
|
+
|
|
316
|
+
- 1
|
|
317
|
+
- 25
|
|
318
|
+
- 99999
|
|
254
319
|
|
|
255
320
|
Invalid Examples
|
|
256
|
-
1.5, -10, abc
|
|
257
321
|
|
|
258
|
-
|
|
322
|
+
- 1.5
|
|
323
|
+
- -10
|
|
324
|
+
- abc
|
|
325
|
+
|
|
326
|
+
### AMOUNT_REGEX
|
|
259
327
|
|
|
260
|
-
AMOUNT_REGEX: /^\d+(\.\d{1,2})
|
|
328
|
+
`AMOUNT_REGEX: /^\d+(\.\d{1,2})?$/`
|
|
261
329
|
|
|
262
330
|
Validates monetary amounts:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
331
|
+
|
|
332
|
+
1. Whole numbers
|
|
333
|
+
2. Optional decimal
|
|
334
|
+
3. Maximum 2 decimal places
|
|
266
335
|
|
|
267
336
|
Valid Examples
|
|
268
|
-
|
|
337
|
+
|
|
338
|
+
- 10,
|
|
339
|
+
- 10.5
|
|
340
|
+
- 10.50
|
|
341
|
+
- 9999.99
|
|
269
342
|
|
|
270
343
|
Invalid Examples
|
|
271
|
-
10., 10.999, abc
|
|
272
344
|
|
|
273
|
-
|
|
345
|
+
- 10.
|
|
346
|
+
- 10.999
|
|
347
|
+
- abc
|
|
274
348
|
|
|
275
|
-
DOMAIN_REGEX
|
|
276
|
-
|
|
349
|
+
### DOMAIN_REGEX
|
|
350
|
+
|
|
351
|
+
`DOMAIN_REGEX: /^(?=.{1,255}$)(https?|ftp):\/\/([\w.-]+)\.([a-z\.]{2,6})(:[0-9]{1,5})?(\/\S*)?$/`
|
|
277
352
|
|
|
278
353
|
Validates full URLs with:
|
|
279
354
|
http, https, or ftp protocol
|
|
280
355
|
|
|
281
356
|
Valid domain
|
|
282
|
-
|
|
283
|
-
Optional
|
|
284
|
-
|
|
357
|
+
|
|
358
|
+
1. Optional port
|
|
359
|
+
2. Optional path
|
|
360
|
+
3. Maximum length of 255 characters
|
|
285
361
|
|
|
286
362
|
Valid Examples
|
|
287
|
-
|
|
363
|
+
|
|
364
|
+
- https://example.com
|
|
365
|
+
- http://sub.domain.org
|
|
366
|
+
- https://example.com:8080/path
|
|
367
|
+
- ftp://files.server.net
|
|
288
368
|
|
|
289
369
|
Invalid Examples
|
|
290
|
-
example.com, http:/example.com, htp://domain.com
|
|
291
370
|
|
|
292
|
-
|
|
371
|
+
- example.com
|
|
372
|
+
- http:/example.com
|
|
373
|
+
- htp://domain.com
|
|
374
|
+
|
|
375
|
+
Usage in Angular Reactive Forms
|
|
293
376
|
|
|
377
|
+
```ts
|
|
294
378
|
this.form = new FormGroup({
|
|
295
|
-
email: new FormControl(
|
|
296
|
-
Validators.pattern(IntellitoolxRegExps.
|
|
297
|
-
]),
|
|
298
|
-
amount: new FormControl('', [
|
|
299
|
-
Validators.pattern(IntellitoolxRegExps.AMOUNT_REGEX),
|
|
300
|
-
]),
|
|
301
|
-
website: new FormControl('', [
|
|
302
|
-
Validators.pattern(IntellitoolxRegExps.DOMAIN_REGEX),
|
|
303
|
-
]),
|
|
379
|
+
email: new FormControl("", [Validators.pattern(IntellitoolxRegExps.EMAIL_REGEX)]),
|
|
380
|
+
amount: new FormControl("", [Validators.pattern(IntellitoolxRegExps.AMOUNT_REGEX)]),
|
|
381
|
+
website: new FormControl("", [Validators.pattern(IntellitoolxRegExps.DOMAIN_REGEX)]),
|
|
304
382
|
});
|
|
383
|
+
```
|
|
305
384
|
|
|
306
385
|
# IntellitoolxFormUpdateMessage
|
|
307
386
|
|
|
@@ -309,159 +388,187 @@ A lightweight Angular standalone component that displays a configurable warning
|
|
|
309
388
|
|
|
310
389
|
Designed to improve user experience by clearly informing users why an action (such as saving) cannot proceed.
|
|
311
390
|
|
|
312
|
-
|
|
391
|
+
### Import
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
import { IntellitoolxFormUpdateMessage } from "intellitoolx";
|
|
395
|
+
```
|
|
313
396
|
|
|
314
|
-
import { IntellitoolxFormUpdateMessage } from 'intellitoolx-helper';
|
|
315
397
|
Because it is standalone, import it directly:
|
|
316
398
|
|
|
399
|
+
```ts
|
|
317
400
|
@Component({
|
|
318
|
-
standalone: true,
|
|
319
|
-
imports: [IntellitoolxFormUpdateMessage],
|
|
401
|
+
standalone: true,
|
|
402
|
+
imports: [IntellitoolxFormUpdateMessage],
|
|
320
403
|
})
|
|
404
|
+
```
|
|
321
405
|
|
|
322
|
-
|
|
406
|
+
Basic Usage
|
|
323
407
|
|
|
408
|
+
```
|
|
324
409
|
<itx-form-update-message></itx-form-update-message>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Default message:
|
|
325
413
|
|
|
326
|
-
|
|
414
|
+
`There are no changes to save. Please modify a field to continue.`
|
|
327
415
|
|
|
328
|
-
|
|
329
|
-
With Configuration
|
|
416
|
+
### With Configuration
|
|
330
417
|
|
|
331
418
|
Customize text and styling using itxFormUpdateMessageConfig.
|
|
332
419
|
|
|
333
|
-
|
|
334
|
-
[itxFormUpdateMessageConfig]="updateMessageConfig"
|
|
420
|
+
```html
|
|
421
|
+
<itx-form-update-message [itxFormUpdateMessageConfig]="updateMessageConfig"> </itx-form-update-message>
|
|
422
|
+
```
|
|
335
423
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
424
|
+
```ts
|
|
425
|
+
updateMessageConfig = {
|
|
426
|
+
message: "Nothing changed yet.",
|
|
427
|
+
textColor: "#0c5460",
|
|
428
|
+
backgroundColor: "#d1ecf1",
|
|
429
|
+
borderColor: "#bee5eb",
|
|
430
|
+
};
|
|
431
|
+
```
|
|
343
432
|
|
|
344
|
-
|
|
433
|
+
Configuration Interface
|
|
345
434
|
|
|
435
|
+
```ts
|
|
346
436
|
export interface IntellitoolxFormUpdateMessageConfig {
|
|
347
|
-
message?: string;
|
|
348
|
-
textColor?: string;
|
|
349
|
-
backgroundColor?: string;
|
|
350
|
-
borderColor?: string;
|
|
351
|
-
padding?: string;
|
|
352
|
-
iconAndMessageGap?: string;
|
|
353
|
-
borderRadius?: string;
|
|
354
|
-
fontWeight?: number | string;
|
|
355
|
-
iconSize?: string;
|
|
437
|
+
message?: string;
|
|
438
|
+
textColor?: string;
|
|
439
|
+
backgroundColor?: string;
|
|
440
|
+
borderColor?: string;
|
|
441
|
+
padding?: string;
|
|
442
|
+
iconAndMessageGap?: string;
|
|
443
|
+
borderRadius?: string;
|
|
444
|
+
fontWeight?: number | string;
|
|
445
|
+
iconSize?: string;
|
|
356
446
|
}
|
|
447
|
+
```
|
|
357
448
|
|
|
358
449
|
All properties are optional.
|
|
359
450
|
|
|
360
|
-
|
|
361
|
-
|
|
451
|
+
Default Styling Behavior
|
|
362
452
|
If no configuration is provided, the component uses accessible warning styles.
|
|
363
453
|
|
|
364
|
-
Property Default
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
454
|
+
| Property | Default |
|
|
455
|
+
| ------------- | ------- |
|
|
456
|
+
| text color | #963C00 |
|
|
457
|
+
| background | #fff3cd |
|
|
458
|
+
| border | #f3cd5a |
|
|
459
|
+
| padding | 1rem |
|
|
460
|
+
| border radius | 0.5rem |
|
|
461
|
+
| gap | 0.5rem |
|
|
462
|
+
| font weight | 400 |
|
|
463
|
+
| icon size | 1rem |
|
|
464
|
+
|
|
373
465
|
Accessibility
|
|
374
466
|
|
|
375
|
-
Uses role="alert" to notify assistive technologies
|
|
376
|
-
Icon is hidden from screen readers with aria-hidden="true"
|
|
377
|
-
Provides clear visual contrast for warning context
|
|
467
|
+
- Uses role="alert" to notify assistive technologies
|
|
468
|
+
- Icon is hidden from screen readers with aria-hidden="true"
|
|
469
|
+
- Provides clear visual contrast for warning context
|
|
378
470
|
|
|
379
471
|
Example: Show When No Changes Exist
|
|
380
|
-
|
|
381
|
-
\*ngIf="!formHasChanges"
|
|
472
|
+
formHasChanges = false;
|
|
382
473
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
> hasChanges = IntelliToolxHelper.formHasChanges(this.initialValue, this.form);
|
|
387
|
-
> <itx-form-update-message
|
|
388
|
-
> *ngIf="!hasChanges"
|
|
389
|
-
> </itx-form-update-message>
|
|
474
|
+
```html
|
|
475
|
+
<itx-form-update-message *ngIf="!formHasChanges"> </itx-form-update-message>
|
|
476
|
+
```
|
|
390
477
|
|
|
391
|
-
|
|
478
|
+
Example: Integrating With IntelliToolxHelper
|
|
392
479
|
|
|
480
|
+
```ts
|
|
481
|
+
hasChanges = IntelliToolxHelper.formHasChanges(this.initialValue, this.form);
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
```html
|
|
485
|
+
<itx-form-update-message *ngIf="!hasChanges"> </itx-form-update-message>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Theming Examples
|
|
393
489
|
Success Style
|
|
490
|
+
|
|
491
|
+
```ts
|
|
394
492
|
updateMessageConfig = {
|
|
395
|
-
message:
|
|
396
|
-
textColor:
|
|
397
|
-
backgroundColor:
|
|
398
|
-
borderColor:
|
|
493
|
+
message: "No updates were made.",
|
|
494
|
+
textColor: "#155724",
|
|
495
|
+
backgroundColor: "#d4edda",
|
|
496
|
+
borderColor: "#c3e6cb",
|
|
399
497
|
};
|
|
498
|
+
```
|
|
400
499
|
|
|
401
500
|
Minimal Style
|
|
501
|
+
|
|
502
|
+
```ts
|
|
402
503
|
updateMessageConfig = {
|
|
403
|
-
backgroundColor:
|
|
404
|
-
borderColor:
|
|
405
|
-
textColor:
|
|
504
|
+
backgroundColor: "transparent",
|
|
505
|
+
borderColor: "#ddd",
|
|
506
|
+
textColor: "#555",
|
|
406
507
|
};
|
|
508
|
+
```
|
|
407
509
|
|
|
408
|
-
|
|
409
|
-
|
|
510
|
+
When to Use
|
|
410
511
|
Use this component when:
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
512
|
+
|
|
513
|
+
1. A save/update action is triggered without changes
|
|
514
|
+
2. Preventing redundant submissions
|
|
515
|
+
3. Improving form UX clarity
|
|
516
|
+
4. Displaying inline form state feedback
|
|
415
517
|
|
|
416
518
|
# IntellitoolxFormErrors
|
|
417
519
|
|
|
418
520
|
A lightweight Angular standalone component for displaying reactive form validation errors with customizable and extensible error messages.
|
|
419
|
-
|
|
420
521
|
Built to:
|
|
421
|
-
standardize validation messages
|
|
422
|
-
support component-level overrides
|
|
423
|
-
allow global extension of error messages
|
|
424
|
-
simplify template error handling
|
|
425
522
|
|
|
426
|
-
|
|
427
|
-
|
|
523
|
+
1. standardize validation messages
|
|
524
|
+
2. support component-level overrides
|
|
525
|
+
3. allow global extension of error messages
|
|
526
|
+
4. simplify template error handling
|
|
527
|
+
|
|
528
|
+
### Import
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
import { IntellitoolxFormErrors } from "intellitoolx";
|
|
532
|
+
```
|
|
428
533
|
|
|
429
534
|
You can import it directly into any component.
|
|
430
535
|
|
|
431
|
-
|
|
536
|
+
### Basic Usage
|
|
432
537
|
|
|
433
|
-
|
|
434
|
-
<itx-form-errors [control]="emailControl"></itx-form-errors>
|
|
538
|
+
```html
|
|
539
|
+
<input [formControl]="emailControl" /> <itx-form-errors [control]="emailControl"></itx-form-errors>
|
|
540
|
+
```
|
|
435
541
|
|
|
436
542
|
Errors will display automatically when:
|
|
437
|
-
control is touched
|
|
438
|
-
control is invalid
|
|
439
543
|
|
|
440
|
-
|
|
544
|
+
- control is touched
|
|
545
|
+
- control is invalid
|
|
546
|
+
|
|
547
|
+
### Default Supported Errors
|
|
548
|
+
|
|
441
549
|
The component includes built-in messages for common validators:
|
|
442
550
|
|
|
443
|
-
Error Key Message
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
controlLabel="Amount"
|
|
463
|
-
|
|
464
|
-
> </itx-form-errors>
|
|
551
|
+
| Error Key | Message |
|
|
552
|
+
| ----------------------------- | ------------------------------------------ |
|
|
553
|
+
| required | This field is required |
|
|
554
|
+
| email | The email entered is invalid |
|
|
555
|
+
| minlength | You must enter at least X characters |
|
|
556
|
+
| maxlength | You must not enter more than X characters |
|
|
557
|
+
| pattern | Your entry must match the required pattern |
|
|
558
|
+
| passwordMismatch | Password and confirm password do not match |
|
|
559
|
+
| futureDate | Future date is not allowed |
|
|
560
|
+
| duplicateEmail | Each email must be unique |
|
|
561
|
+
| maxWords | Exceeded maximum number of words |
|
|
562
|
+
| maxMonthYear | Date is later than allowed |
|
|
563
|
+
| minMonthYear | Date is earlier than allowed |
|
|
564
|
+
| exceededAllowedDateDifference | Date difference can only be one month |
|
|
565
|
+
| exceededLeastDateAllowed | Start date cannot be greater than end date |
|
|
566
|
+
|
|
567
|
+
### Adding Control Labels (User-Friendly Messages)
|
|
568
|
+
|
|
569
|
+
```html
|
|
570
|
+
<itx-form-errors [control]="amountControl" controlLabel="Amount"> </itx-form-errors>
|
|
571
|
+
```
|
|
465
572
|
|
|
466
573
|
Example output:
|
|
467
574
|
Amount cannot be greater than 100
|
|
@@ -469,491 +576,570 @@ Amount cannot be greater than 100
|
|
|
469
576
|
Component-Level Custom Messages
|
|
470
577
|
Override messages for a specific field.
|
|
471
578
|
|
|
579
|
+
```ts
|
|
472
580
|
componentValidation = {
|
|
473
|
-
required: { message:
|
|
474
|
-
minlength: { message:
|
|
581
|
+
required: { message: "Email is mandatory" },
|
|
582
|
+
minlength: { message: "Too short" },
|
|
475
583
|
};
|
|
584
|
+
```
|
|
476
585
|
|
|
477
|
-
|
|
478
|
-
[control]="emailControl"
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
> </itx-form-errors>
|
|
586
|
+
```html
|
|
587
|
+
<itx-form-errors [control]="emailControl" [componentValidation]="componentValidation"> </itx-form-errors>
|
|
588
|
+
```
|
|
482
589
|
|
|
483
590
|
### Using Custom Validators with Messages
|
|
484
591
|
|
|
485
592
|
If your validator returns an object:
|
|
486
|
-
|
|
593
|
+
|
|
594
|
+
```ts
|
|
595
|
+
return { customMinValue: { message: "Value is too small" } };
|
|
596
|
+
```
|
|
487
597
|
|
|
488
598
|
The component will display:
|
|
489
599
|
Value is too small
|
|
490
600
|
|
|
491
|
-
|
|
601
|
+
### Extending Error Messages (Recommended)
|
|
492
602
|
|
|
493
603
|
Consumers can extend the component to add global or shared messages.
|
|
494
604
|
|
|
495
|
-
|
|
605
|
+
Option 1 — Extend the Component
|
|
496
606
|
|
|
497
607
|
Create your own reusable error component:
|
|
498
608
|
|
|
499
|
-
|
|
500
|
-
import {
|
|
609
|
+
```ts
|
|
610
|
+
import { Component } from "@angular/core";
|
|
611
|
+
import { IntellitoolxFormErrors } from "intellitoolx";
|
|
501
612
|
|
|
502
613
|
@Component({
|
|
503
|
-
selector:
|
|
504
|
-
standalone: true,
|
|
505
|
-
imports: [IntellitoolxFormErrors],
|
|
506
|
-
template: `
|
|
507
|
-
[control]="control"
|
|
508
|
-
[componentValidation]="componentValidation"
|
|
509
|
-
[controlLabel]="controlLabel"
|
|
510
|
-
/>
|
|
511
|
-
`,
|
|
614
|
+
selector: "app-form-errors",
|
|
615
|
+
standalone: true,
|
|
616
|
+
imports: [IntellitoolxFormErrors],
|
|
617
|
+
template: ` <itx-form-errors [control]="control" [componentValidation]="componentValidation" [controlLabel]="controlLabel" /> `,
|
|
512
618
|
})
|
|
513
619
|
export class AppFormErrors extends IntellitoolxFormErrors {
|
|
514
|
-
override errorMessages = {
|
|
515
|
-
...this.errorMessages,
|
|
516
|
-
required:
|
|
517
|
-
phone:
|
|
518
|
-
usernameTaken:
|
|
519
|
-
};
|
|
620
|
+
override errorMessages = {
|
|
621
|
+
...this.errorMessages,
|
|
622
|
+
required: "This field cannot be empty",
|
|
623
|
+
phone: "Phone number is invalid",
|
|
624
|
+
usernameTaken: "This username is already taken",
|
|
625
|
+
};
|
|
520
626
|
}
|
|
627
|
+
```
|
|
521
628
|
|
|
522
629
|
Now use:
|
|
630
|
+
|
|
631
|
+
```html
|
|
523
632
|
<app-form-errors [control]="control"></app-form-errors>
|
|
633
|
+
```
|
|
524
634
|
|
|
525
|
-
|
|
635
|
+
Option 2 — Extend via Custom Validator Keys
|
|
526
636
|
|
|
527
637
|
Return new error keys from validators:
|
|
528
638
|
|
|
639
|
+
```ts
|
|
529
640
|
return { usernameTaken: true };
|
|
641
|
+
```
|
|
530
642
|
|
|
531
643
|
Then provide the message:
|
|
532
644
|
|
|
645
|
+
```ts
|
|
533
646
|
componentValidation = {
|
|
534
|
-
usernameTaken: { message:
|
|
647
|
+
usernameTaken: { message: "Username already exists" },
|
|
535
648
|
};
|
|
649
|
+
```
|
|
536
650
|
|
|
537
|
-
|
|
651
|
+
Option 3 — Global Shared Messages Service (Advanced)
|
|
538
652
|
|
|
539
653
|
Create a shared constant:
|
|
540
654
|
|
|
655
|
+
```ts
|
|
541
656
|
export const APP_ERROR_MESSAGES = {
|
|
542
|
-
required:
|
|
543
|
-
email:
|
|
657
|
+
required: "Required field",
|
|
658
|
+
email: "Invalid email address",
|
|
544
659
|
};
|
|
660
|
+
```
|
|
545
661
|
|
|
546
662
|
Then extend:
|
|
663
|
+
|
|
664
|
+
```ts
|
|
547
665
|
override errorMessages = {
|
|
548
666
|
...APP_ERROR_MESSAGES,
|
|
549
667
|
};
|
|
668
|
+
```
|
|
550
669
|
|
|
551
|
-
|
|
670
|
+
### Supported Error Value Types
|
|
552
671
|
|
|
553
672
|
The component intelligently handles different validator outputs:
|
|
554
673
|
|
|
555
|
-
Boolean
|
|
556
|
-
{
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
String
|
|
560
|
-
{ customError: 'Invalid value provided' }
|
|
561
|
-
→ displays string directly
|
|
562
|
-
|
|
563
|
-
Object
|
|
564
|
-
{ minlength: { requiredLength: 5 } }
|
|
565
|
-
→ dynamic message rendering
|
|
674
|
+
- Boolean { required: true } → uses default or custom message
|
|
675
|
+
- String { customError: 'Invalid value provided' } → displays string directly
|
|
676
|
+
- Object { minlength: { requiredLength: 5 } } → dynamic message rendering
|
|
566
677
|
|
|
567
678
|
Built-in Smart Messages
|
|
568
|
-
Pattern Errors
|
|
569
679
|
|
|
570
|
-
|
|
680
|
+
- Pattern Errors Display: `Please provide a valid {controlLabel}`
|
|
681
|
+
- Min / Max Validators Display: `Age cannot be less than 18` / `Price cannot be greater than 100`
|
|
682
|
+
- Ngb Date Errors Display: `Invalid date format provided`
|
|
571
683
|
|
|
572
|
-
|
|
573
|
-
Min / Max Validators
|
|
574
|
-
Age cannot be less than 18
|
|
575
|
-
Price cannot be greater than 100
|
|
576
|
-
Ngb Date Errors
|
|
577
|
-
Invalid date format provided
|
|
684
|
+
Best Practices
|
|
578
685
|
|
|
579
|
-
|
|
686
|
+
- Always provide controlLabel for better UX
|
|
687
|
+
- Use componentValidation for field-specific overrides
|
|
688
|
+
- Extend the component for app-wide consistency
|
|
689
|
+
- Return structured error objects from custom validators
|
|
690
|
+
- Keep error keys consistent across the application
|
|
580
691
|
|
|
581
|
-
|
|
582
|
-
✔ Use componentValidation for field-specific overrides
|
|
583
|
-
✔ Extend the component for app-wide consistency
|
|
584
|
-
✔ Return structured error objects from custom validators
|
|
585
|
-
✔ Keep error keys consistent across the application
|
|
692
|
+
### Example (Full Integration)
|
|
586
693
|
|
|
587
|
-
|
|
694
|
+
```html
|
|
588
695
|
<input formControlName="email" />
|
|
589
696
|
|
|
590
|
-
<app-form-errors
|
|
591
|
-
|
|
592
|
-
controlLabel="Email Address"
|
|
593
|
-
|
|
594
|
-
> </app-form-errors>
|
|
697
|
+
<app-form-errors [control]="form.controls.email" controlLabel="Email Address"> </app-form-errors>
|
|
698
|
+
```
|
|
595
699
|
|
|
596
700
|
# RequiredMarkerDirective
|
|
597
701
|
|
|
598
702
|
An Angular standalone directive that automatically adds a visual required marker to form labels when the associated form control has a required validator.
|
|
599
703
|
This ensures consistent UX and eliminates manual asterisk management.
|
|
600
704
|
|
|
601
|
-
|
|
705
|
+
### Import
|
|
602
706
|
|
|
603
|
-
|
|
707
|
+
```ts
|
|
708
|
+
import { RequiredMarkerDirective } from "intellitoolx";
|
|
709
|
+
```
|
|
604
710
|
|
|
605
711
|
Because it is standalone, import it directly:
|
|
606
712
|
|
|
713
|
+
```ts
|
|
607
714
|
@Component({
|
|
608
|
-
standalone: true,
|
|
609
|
-
imports: [RequiredMarkerDirective],
|
|
715
|
+
standalone: true,
|
|
716
|
+
imports: [RequiredMarkerDirective],
|
|
610
717
|
})
|
|
718
|
+
```
|
|
611
719
|
|
|
612
|
-
|
|
720
|
+
### Basic Usage
|
|
613
721
|
|
|
614
722
|
Add the directive to a <label> element.
|
|
615
723
|
|
|
724
|
+
```html
|
|
616
725
|
<label for="email" itxRequired>Email</label>
|
|
726
|
+
|
|
617
727
|
<input id="email" formControlName="email" />
|
|
728
|
+
```
|
|
618
729
|
|
|
619
730
|
If the control has Validators.required, the output becomes:
|
|
620
|
-
Email
|
|
731
|
+
Email\*
|
|
621
732
|
|
|
622
|
-
|
|
733
|
+
### How It Works
|
|
623
734
|
|
|
624
|
-
Reads the label’s for attribute.
|
|
625
|
-
Finds the matching control inside the parent FormGroup.
|
|
626
|
-
Checks for Validators.required.
|
|
627
|
-
Adds or removes the required marker dynamically.
|
|
628
|
-
Updates when value or status changes.
|
|
629
|
-
|
|
630
|
-
## Dynamic Updates
|
|
735
|
+
- Reads the label’s for attribute.
|
|
736
|
+
- Finds the matching control inside the parent FormGroup.
|
|
737
|
+
- Checks for Validators.required.
|
|
738
|
+
- Adds or removes the required marker dynamically.
|
|
739
|
+
- Updates when value or status changes.
|
|
631
740
|
|
|
741
|
+
Dynamic Updates
|
|
632
742
|
If required validation is added or removed at runtime:
|
|
743
|
+
|
|
744
|
+
```ts
|
|
633
745
|
control.setValidators([Validators.required]);
|
|
634
746
|
control.updateValueAndValidity();
|
|
747
|
+
```
|
|
748
|
+
|
|
635
749
|
The label updates automatically.
|
|
636
750
|
|
|
637
|
-
|
|
751
|
+
### Default Marker Behavior
|
|
638
752
|
|
|
639
|
-
Property Default
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
753
|
+
| Property | Default |
|
|
754
|
+
| -------------------- | ------- |
|
|
755
|
+
| marker sign | \* |
|
|
756
|
+
| color | red |
|
|
757
|
+
| spacing | 0.25rem |
|
|
758
|
+
| position after label | text |
|
|
645
759
|
|
|
646
|
-
|
|
760
|
+
### Global Configuration
|
|
647
761
|
|
|
762
|
+
You can configure marker appearance globally using the provided injection token.
|
|
648
763
|
Step 1 — Provide Configuration
|
|
649
|
-
|
|
764
|
+
|
|
765
|
+
```ts
|
|
766
|
+
import { REQUIRED_MARKER_GLOBAL_CONFIG } from "intellitoolx";
|
|
650
767
|
|
|
651
768
|
providers: [
|
|
652
|
-
{
|
|
653
|
-
provide: REQUIRED_MARKER_GLOBAL_CONFIG,
|
|
654
|
-
useValue: {
|
|
655
|
-
sign:
|
|
656
|
-
color:
|
|
657
|
-
spacing:
|
|
658
|
-
position:
|
|
659
|
-
},
|
|
660
|
-
},
|
|
769
|
+
{
|
|
770
|
+
provide: REQUIRED_MARKER_GLOBAL_CONFIG,
|
|
771
|
+
useValue: {
|
|
772
|
+
sign: "*",
|
|
773
|
+
color: "#d9534f",
|
|
774
|
+
spacing: "4px",
|
|
775
|
+
position: "after", // 'before' | 'after'
|
|
776
|
+
},
|
|
777
|
+
},
|
|
661
778
|
];
|
|
779
|
+
```
|
|
662
780
|
|
|
663
781
|
Configuration Options
|
|
782
|
+
|
|
783
|
+
```ts
|
|
664
784
|
export interface ResolvedRequiredMarkerConfig {
|
|
665
|
-
sign: string;
|
|
666
|
-
color: string;
|
|
667
|
-
spacing: string;
|
|
668
|
-
position:
|
|
785
|
+
sign: string;
|
|
786
|
+
color: string;
|
|
787
|
+
spacing: string;
|
|
788
|
+
position: "before" | "after";
|
|
669
789
|
}
|
|
790
|
+
```
|
|
670
791
|
|
|
671
792
|
Positioning the Marker
|
|
672
|
-
After (default)
|
|
673
|
-
Email
|
|
674
|
-
Before
|
|
675
|
-
position: 'before'
|
|
676
|
-
|
|
677
|
-
- Email
|
|
793
|
+
After (default) `Email \*`
|
|
794
|
+
Before position: 'before' `\* Email`
|
|
678
795
|
|
|
679
796
|
Preserves Additional Label Text
|
|
680
797
|
The directive preserves text in parentheses or suffix content.
|
|
798
|
+
|
|
799
|
+
```html
|
|
681
800
|
<label for="dob" itxRequired>Date of Birth (optional)</label>
|
|
801
|
+
```
|
|
682
802
|
|
|
683
|
-
Output when required:
|
|
684
|
-
Date of Birth \* (optional)
|
|
803
|
+
Output when required: `Date of Birth \* (optional)`
|
|
685
804
|
Works With Nested Form Groups
|
|
686
|
-
Ensure the for attribute matches the control name.
|
|
805
|
+
Ensure the `for` attribute matches the control name.
|
|
806
|
+
|
|
807
|
+
```html
|
|
687
808
|
<label for="address.street" itxRequired>Street</label>
|
|
809
|
+
|
|
688
810
|
<input formControlName="street" />
|
|
811
|
+
```
|
|
689
812
|
|
|
690
|
-
|
|
813
|
+
### Requirements
|
|
691
814
|
|
|
692
|
-
Must be used inside a form with FormGroupDirective
|
|
693
|
-
Label for attribute must match control name
|
|
815
|
+
- Must be used inside a form with FormGroupDirective
|
|
816
|
+
- Label for attribute must match control name
|
|
694
817
|
|
|
695
|
-
|
|
818
|
+
### Common Mistakes
|
|
696
819
|
|
|
697
|
-
Missing for attribute
|
|
698
|
-
Label not associated with control
|
|
699
|
-
Control name mismatch
|
|
820
|
+
- Missing for attribute
|
|
821
|
+
- Label not associated with control
|
|
822
|
+
- Control name mismatch
|
|
700
823
|
|
|
701
824
|
Example (Complete)
|
|
702
825
|
|
|
826
|
+
```html
|
|
703
827
|
<form [formGroup]="form">
|
|
704
828
|
<label for="email" itxRequired>Email</label>
|
|
705
829
|
<input id="email" formControlName="email" />
|
|
706
830
|
</form>
|
|
707
|
-
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
```ts
|
|
834
|
+
email: new FormControl("", Validators.required);
|
|
835
|
+
```
|
|
708
836
|
|
|
709
837
|
# JsonParsePipe
|
|
710
838
|
|
|
711
839
|
An Angular standalone pipe that safely parses JSON strings into JavaScript objects.
|
|
840
|
+
Built on top of `IntelliToolxHelper.convertJsonStringToJson`, this pipe prevents template errors when dealing with dynamic or stringified JSON data.
|
|
712
841
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
## Import
|
|
842
|
+
### Import
|
|
716
843
|
|
|
717
|
-
|
|
844
|
+
```ts
|
|
845
|
+
import { JsonParsePipe } from "intellitoolx";
|
|
846
|
+
```
|
|
718
847
|
|
|
719
848
|
Because it is standalone, import it directly:
|
|
720
849
|
|
|
850
|
+
```ts
|
|
721
851
|
@Component({
|
|
722
|
-
standalone: true,
|
|
723
|
-
imports: [JsonParsePipe],
|
|
852
|
+
standalone: true,
|
|
853
|
+
imports: [JsonParsePipe],
|
|
724
854
|
})
|
|
855
|
+
```
|
|
725
856
|
|
|
726
|
-
|
|
857
|
+
### Usage
|
|
727
858
|
|
|
728
859
|
Basic Example
|
|
860
|
+
|
|
861
|
+
```
|
|
729
862
|
{{ jsonString | jsonParse | json }}
|
|
863
|
+
```
|
|
730
864
|
|
|
731
865
|
Input
|
|
866
|
+
|
|
867
|
+
```ts
|
|
732
868
|
jsonString = '{"name":"John","age":30}';
|
|
869
|
+
```
|
|
733
870
|
|
|
734
871
|
Output
|
|
872
|
+
|
|
873
|
+
```json
|
|
735
874
|
{
|
|
736
|
-
"name": "John",
|
|
737
|
-
"age": 30
|
|
875
|
+
"name": "John",
|
|
876
|
+
"age": 30
|
|
738
877
|
}
|
|
878
|
+
```
|
|
739
879
|
|
|
740
|
-
|
|
880
|
+
### When to Use
|
|
741
881
|
|
|
742
882
|
Use jsonParse when:
|
|
743
|
-
API responses contain stringified JSON
|
|
744
|
-
Form values store serialized objects
|
|
745
|
-
LocalStorage data needs parsing
|
|
746
|
-
Preventing template crashes from invalid JSON
|
|
747
883
|
|
|
748
|
-
|
|
884
|
+
- API responses contain stringified JSON
|
|
885
|
+
- Form values store serialized objects
|
|
886
|
+
- LocalStorage data needs parsing
|
|
887
|
+
- Preventing template crashes from invalid JSON
|
|
888
|
+
|
|
889
|
+
### Behavior
|
|
749
890
|
|
|
750
891
|
The pipe safely handles multiple input types:
|
|
751
892
|
|
|
752
|
-
Input Result
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
893
|
+
| Input | Result |
|
|
894
|
+
| ------------------------ | --------- |
|
|
895
|
+
| Valid JSON string Parsed | object |
|
|
896
|
+
| Invalid JSON string | null |
|
|
897
|
+
| Object Returned | unchanged |
|
|
898
|
+
| null / undefined | null |
|
|
757
899
|
|
|
758
900
|
Examples
|
|
759
901
|
Parse API Data
|
|
760
902
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
903
|
+
```html
|
|
904
|
+
<div *ngIf="user.data | jsonParse as parsed">{{ parsed.name }}</div>
|
|
905
|
+
```
|
|
764
906
|
|
|
765
907
|
Parse Stored JSON
|
|
908
|
+
|
|
909
|
+
```
|
|
766
910
|
{{ localStorageValue | jsonParse | json }}
|
|
911
|
+
```
|
|
767
912
|
|
|
768
913
|
Safe Access with Optional Chaining
|
|
914
|
+
|
|
915
|
+
```
|
|
769
916
|
{{ (settings | jsonParse)?.theme }}
|
|
917
|
+
```
|
|
770
918
|
|
|
771
919
|
Equivalent TypeScript Logic
|
|
772
920
|
|
|
773
921
|
The pipe internally performs:
|
|
922
|
+
|
|
923
|
+
```ts
|
|
774
924
|
IntelliToolxHelper.convertJsonStringToJson(value);
|
|
925
|
+
```
|
|
775
926
|
|
|
776
927
|
Error Safety
|
|
928
|
+
|
|
777
929
|
Unlike JSON.parse() directly in templates, this pipe:
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
930
|
+
|
|
931
|
+
- prevents runtime template errors
|
|
932
|
+
- avoids breaking change detection
|
|
933
|
+
- returns null on parsing failure
|
|
781
934
|
|
|
782
935
|
For large datasets or repeated bindings:
|
|
783
936
|
Prefer parsing in the component
|
|
937
|
+
|
|
938
|
+
```ts
|
|
784
939
|
parsedData = IntelliToolxHelper.convertJsonStringToJson(data);
|
|
940
|
+
```
|
|
785
941
|
|
|
786
942
|
# IntelliToolx Validators
|
|
787
943
|
|
|
788
944
|
A set of reusable Angular Reactive Form validators designed for common business rules such as amount limits, password matching, word limits, and duplicate detection.
|
|
789
|
-
|
|
790
|
-
These validators integrate seamlessly with Angular forms and work perfectly with IntellitoolxFormErrors for displaying user-friendly messages.
|
|
945
|
+
These validators integrate seamlessly with Angular forms and work perfectly with `IntellitoolxFormErrors` for displaying user-friendly messages.
|
|
791
946
|
|
|
792
947
|
Import
|
|
793
|
-
import {
|
|
794
|
-
customMaxAmountValidator,
|
|
795
|
-
customMinAmountValidator,
|
|
796
|
-
MaxWordsValidator,
|
|
797
|
-
PasswordMismatchValidator,
|
|
798
|
-
uniqueEmailsValidator
|
|
799
|
-
} from 'intellitoolx-helper';
|
|
800
948
|
|
|
801
|
-
|
|
949
|
+
```ts
|
|
950
|
+
import { customMaxAmountValidator, customMinAmountValidator, maxWordsValidator, passwordMismatchValidator, uniqueEmailsValidator } from "intellitoolx";
|
|
951
|
+
```
|
|
802
952
|
|
|
803
|
-
|
|
804
|
-
customMaxAmountValidator Enforces maximum numeric value
|
|
805
|
-
customMinAmountValidator Enforces minimum numeric value
|
|
806
|
-
MaxWordsValidator Limits number of words
|
|
807
|
-
PasswordMismatchValidator Ensures password fields match
|
|
808
|
-
uniqueEmailsValidator Prevents duplicate emails in FormArray
|
|
953
|
+
### Validators Overview
|
|
809
954
|
|
|
810
|
-
|
|
955
|
+
| Validator | Purpose |
|
|
956
|
+
| ------------------------- | -------------------------------------- |
|
|
957
|
+
| customMaxAmountValidator | Enforces maximum numeric value |
|
|
958
|
+
| customMinAmountValidator | Enforces minimum numeric value |
|
|
959
|
+
| maxWordsValidator | Limits number of words |
|
|
960
|
+
| passwordMismatchValidator | Ensures password fields match |
|
|
961
|
+
| uniqueEmailsValidator | Prevents duplicate emails in FormArray |
|
|
962
|
+
|
|
963
|
+
### customMaxAmountValidator(maxValue)
|
|
811
964
|
|
|
812
965
|
Ensures a numeric value does not exceed a specified maximum.
|
|
966
|
+
|
|
967
|
+
```ts
|
|
813
968
|
customMaxAmountValidator(maxValue: number): ValidatorFn
|
|
969
|
+
```
|
|
814
970
|
|
|
815
971
|
Example
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
]);
|
|
972
|
+
|
|
973
|
+
```ts
|
|
974
|
+
amount = new FormControl("", [customMaxAmountValidator(1000)]);
|
|
975
|
+
```
|
|
819
976
|
|
|
820
977
|
Error Output
|
|
978
|
+
|
|
979
|
+
```json
|
|
821
980
|
{
|
|
822
|
-
customMaxValue: {
|
|
823
|
-
requiredMin: 1000,
|
|
824
|
-
actual: 1200,
|
|
825
|
-
message: "The value must not exceed 1000.00"
|
|
826
|
-
}
|
|
981
|
+
"customMaxValue": {
|
|
982
|
+
"requiredMin": 1000,
|
|
983
|
+
"actual": 1200,
|
|
984
|
+
"message": "The value must not exceed 1000.00"
|
|
985
|
+
}
|
|
827
986
|
}
|
|
987
|
+
```
|
|
828
988
|
|
|
829
989
|
Notes
|
|
830
|
-
Accepts numeric values only
|
|
831
|
-
Returns a formatted error message
|
|
832
|
-
Works with IntellitoolxFormErrors automatically
|
|
833
990
|
|
|
834
|
-
|
|
991
|
+
- Accepts numeric values only
|
|
992
|
+
- Returns a formatted error message
|
|
993
|
+
- Works with IntellitoolxFormErrors automatically
|
|
994
|
+
|
|
995
|
+
### customMinAmountValidator(minValue)
|
|
835
996
|
|
|
836
997
|
Ensures a numeric value is at least the specified minimum.
|
|
998
|
+
|
|
999
|
+
```ts
|
|
837
1000
|
customMinAmountValidator(minValue: number): ValidatorFn
|
|
1001
|
+
```
|
|
838
1002
|
|
|
839
1003
|
Example
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
]);
|
|
1004
|
+
|
|
1005
|
+
```ts
|
|
1006
|
+
amount = new FormControl("", [customMinAmountValidator(10)]);
|
|
1007
|
+
```
|
|
1008
|
+
|
|
843
1009
|
Error Output
|
|
1010
|
+
|
|
1011
|
+
```json
|
|
844
1012
|
{
|
|
845
|
-
customMinValue: {
|
|
846
|
-
requiredMin: 10,
|
|
847
|
-
actual: 5,
|
|
848
|
-
message: "The value must be at least 10.00"
|
|
849
|
-
}
|
|
1013
|
+
"customMinValue": {
|
|
1014
|
+
"requiredMin": 10,
|
|
1015
|
+
"actual": 5,
|
|
1016
|
+
"message": "The value must be at least 10.00"
|
|
1017
|
+
}
|
|
850
1018
|
}
|
|
1019
|
+
```
|
|
851
1020
|
|
|
852
|
-
|
|
1021
|
+
### maxWordsValidator(maxWords)
|
|
853
1022
|
|
|
854
1023
|
Limits the number of words in a text input.
|
|
855
|
-
|
|
1024
|
+
maxWordsValidator(maxWords: number): ValidatorFn
|
|
856
1025
|
|
|
857
1026
|
Example
|
|
858
|
-
description = new FormControl('', [
|
|
859
|
-
MaxWordsValidator(20)
|
|
860
|
-
]);
|
|
861
1027
|
|
|
862
|
-
|
|
1028
|
+
```ts
|
|
1029
|
+
description = new FormControl("", [maxWordsValidator(20)]);
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
Behavior
|
|
863
1033
|
|
|
864
|
-
Ignores extra whitespace
|
|
865
|
-
Counts words separated by spaces
|
|
1034
|
+
- Ignores extra whitespace
|
|
1035
|
+
- Counts words separated by spaces
|
|
866
1036
|
|
|
867
1037
|
Error Output
|
|
1038
|
+
|
|
1039
|
+
```json
|
|
868
1040
|
{
|
|
869
|
-
maxWords: {
|
|
870
|
-
actual: 25,
|
|
871
|
-
max: 20
|
|
872
|
-
}
|
|
1041
|
+
"maxWords": {
|
|
1042
|
+
"actual": 25,
|
|
1043
|
+
"max": 20
|
|
1044
|
+
}
|
|
873
1045
|
}
|
|
1046
|
+
```
|
|
874
1047
|
|
|
875
|
-
|
|
1048
|
+
### passwordMismatchValidator(controlName, matchingControlName)
|
|
876
1049
|
|
|
877
1050
|
Validates that two form fields match (commonly used for password confirmation).
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1051
|
+
|
|
1052
|
+
```ts
|
|
1053
|
+
passwordMismatchValidator(
|
|
1054
|
+
controlName: string,
|
|
1055
|
+
matchingControlName: string
|
|
881
1056
|
)
|
|
1057
|
+
```
|
|
882
1058
|
|
|
883
1059
|
Example
|
|
1060
|
+
|
|
1061
|
+
```ts
|
|
884
1062
|
this.form = new FormGroup(
|
|
885
|
-
{
|
|
886
|
-
password: new FormControl(
|
|
887
|
-
confirmPassword: new FormControl(
|
|
888
|
-
},
|
|
889
|
-
{
|
|
890
|
-
validators:
|
|
891
|
-
}
|
|
1063
|
+
{
|
|
1064
|
+
password: new FormControl(""),
|
|
1065
|
+
confirmPassword: new FormControl(""),
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
validators: passwordMismatchValidator("password", "confirmPassword"),
|
|
1069
|
+
},
|
|
892
1070
|
);
|
|
1071
|
+
```
|
|
893
1072
|
|
|
894
1073
|
Error Output
|
|
1074
|
+
|
|
1075
|
+
```
|
|
895
1076
|
{ passwordMismatch: true }
|
|
1077
|
+
```
|
|
896
1078
|
|
|
897
1079
|
Notes
|
|
898
|
-
Error is applied to the matching control
|
|
899
|
-
Ideal for password confirmation fields
|
|
900
1080
|
|
|
901
|
-
|
|
1081
|
+
- Error is applied to the matching control
|
|
1082
|
+
- Ideal for password confirmation fields
|
|
1083
|
+
|
|
1084
|
+
### uniqueEmailsValidator()
|
|
902
1085
|
|
|
903
1086
|
Ensures all email addresses inside a FormArray are unique.
|
|
1087
|
+
|
|
1088
|
+
```ts
|
|
904
1089
|
uniqueEmailsValidator(): ValidatorFn
|
|
1090
|
+
```
|
|
905
1091
|
|
|
906
1092
|
Example
|
|
1093
|
+
|
|
1094
|
+
```ts
|
|
907
1095
|
this.form = new FormGroup({
|
|
908
|
-
contacts: new FormArray([
|
|
909
|
-
new FormGroup({
|
|
910
|
-
email: new FormControl(
|
|
911
|
-
})
|
|
912
|
-
])
|
|
1096
|
+
contacts: new FormArray([
|
|
1097
|
+
new FormGroup({
|
|
1098
|
+
email: new FormControl(""),
|
|
1099
|
+
}),
|
|
1100
|
+
]),
|
|
913
1101
|
});
|
|
914
1102
|
|
|
915
1103
|
this.contacts.setValidators(uniqueEmailsValidator());
|
|
1104
|
+
```
|
|
916
1105
|
|
|
917
|
-
|
|
1106
|
+
Behavior
|
|
918
1107
|
|
|
919
|
-
Ignores case and whitespace
|
|
920
|
-
Flags duplicates automatically
|
|
921
|
-
Updates errors dynamically
|
|
1108
|
+
- Ignores case and whitespace
|
|
1109
|
+
- Flags duplicates automatically
|
|
1110
|
+
- Updates errors dynamically
|
|
922
1111
|
|
|
923
|
-
Error Output (control level)
|
|
924
|
-
{
|
|
925
|
-
Error Output (form array level)
|
|
926
|
-
{ duplicateEmails: true }
|
|
1112
|
+
Error Output (control level) `{ duplicateEmail: true }`
|
|
1113
|
+
Error Output (form array level) `{ duplicateEmails: true }`
|
|
927
1114
|
|
|
928
1115
|
### Integration with IntellitoolxFormErrors
|
|
929
1116
|
|
|
930
1117
|
These validators return error keys compatible with the error component:
|
|
931
|
-
Validator Error Key
|
|
932
|
-
customMaxAmountValidator customMaxValue
|
|
933
|
-
customMinAmountValidator customMinValue
|
|
934
|
-
MaxWordsValidator maxWords
|
|
935
|
-
PasswordMismatchValidator passwordMismatch
|
|
936
|
-
uniqueEmailsValidator duplicateEmail
|
|
937
1118
|
|
|
938
|
-
|
|
1119
|
+
| Validator Error | Key |
|
|
1120
|
+
| ------------------------- | ---------------- |
|
|
1121
|
+
| customMaxAmountValidator | customMaxValue |
|
|
1122
|
+
| customMinAmountValidator | customMinValue |
|
|
1123
|
+
| maxWordsValidator | maxWords |
|
|
1124
|
+
| passwordMismatchValidator | passwordMismatch |
|
|
1125
|
+
| uniqueEmailsValidator | duplicateEmail |
|
|
1126
|
+
|
|
1127
|
+
Best Practices
|
|
939
1128
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1129
|
+
- Use with Reactive Forms only
|
|
1130
|
+
- Combine with required validators when necessary
|
|
1131
|
+
- Provide control labels for better error messages
|
|
1132
|
+
- Normalize numeric inputs before validation
|
|
1133
|
+
- Use FormArray validators for dynamic lists
|
|
945
1134
|
|
|
946
1135
|
### Complete Example
|
|
947
1136
|
|
|
1137
|
+
```ts
|
|
948
1138
|
this.form = new FormGroup({
|
|
949
|
-
amount: new FormControl(
|
|
950
|
-
|
|
951
|
-
customMaxAmountValidator(1000),
|
|
952
|
-
]),
|
|
953
|
-
description: new FormControl('', [
|
|
954
|
-
MaxWordsValidator(20)
|
|
955
|
-
]),
|
|
1139
|
+
amount: new FormControl("", [customMinAmountValidator(10), customMaxAmountValidator(1000)]),
|
|
1140
|
+
description: new FormControl("", [maxWordsValidator(20)]),
|
|
956
1141
|
});
|
|
1142
|
+
```
|
|
957
1143
|
|
|
958
1144
|
License
|
|
959
1145
|
MIT
|