0
# Validation
1
2
Validation system with custom validators, validation messages, and error handling components for comprehensive form validation.
3
4
## Capabilities
5
6
### FormlyValidationMessage
7
8
Component for displaying validation error messages with customizable message rendering.
9
10
```typescript { .api }
11
/**
12
* Component for displaying field validation messages
13
*/
14
@Component({
15
selector: 'formly-validation-message',
16
template: `<div class="error-message">{{ errorMessage }}</div>`
17
})
18
export class FormlyValidationMessage implements OnInit {
19
/** The field configuration containing validation state */
20
@Input() field: FormlyFieldConfig;
21
22
/** The current error message to display */
23
errorMessage: string;
24
}
25
```
26
27
**Usage Example:**
28
29
```typescript
30
@Component({
31
template: `
32
<div class="form-field">
33
<input [formControl]="formControl" [formlyAttributes]="field">
34
<formly-validation-message
35
*ngIf="showError"
36
[field]="field">
37
</formly-validation-message>
38
</div>
39
`
40
})
41
export class CustomFieldComponent extends FieldType {
42
get showError() {
43
return this.field.showError && this.formControl.invalid;
44
}
45
}
46
```
47
48
### FormlyAttributes
49
50
Directive for applying field attributes and handling focus, blur, and change events.
51
52
```typescript { .api }
53
/**
54
* Directive for applying field attributes and event handling
55
*/
56
@Directive({
57
selector: '[formlyAttributes]',
58
host: {
59
'(focus)': 'onFocus($event)',
60
'(blur)': 'onBlur($event)',
61
'(change)': 'onChange($event)',
62
}
63
})
64
export class FormlyAttributes implements OnInit, DoCheck {
65
/** The field configuration */
66
@Input('formlyAttributes') field: FormlyFieldConfig;
67
68
/** Focus event handler */
69
onFocus(event: Event): void;
70
71
/** Blur event handler */
72
onBlur(event: Event): void;
73
74
/** Change event handler */
75
onChange(event: Event): void;
76
}
77
```
78
79
**Usage Example:**
80
81
```typescript
82
@Component({
83
template: `
84
<input
85
[formControl]="formControl"
86
[formlyAttributes]="field"
87
[placeholder]="props.placeholder"
88
[disabled]="props.disabled">
89
`
90
})
91
export class InputFieldComponent extends FieldType {}
92
```
93
94
### Validation Configuration
95
96
Field-level validation configuration supporting both sync and async validators.
97
98
```typescript { .api }
99
/**
100
* Validation configuration for individual fields
101
*/
102
interface FormlyFieldConfigValidators {
103
[key: string]: FormlyValidatorConfig | ValidatorFn | AsyncValidatorFn;
104
}
105
106
interface FormlyValidatorConfig {
107
/** The validator function */
108
validation: ValidatorFn | AsyncValidatorFn;
109
110
/** Options passed to the validator */
111
options?: any;
112
113
/** Custom error message for this validator */
114
message?: string | ((error: any, field: FormlyFieldConfig) => string);
115
}
116
```
117
118
**Usage Example:**
119
120
```typescript
121
const fieldConfig: FormlyFieldConfig = {
122
key: 'email',
123
type: 'input',
124
props: {
125
label: 'Email Address',
126
required: true,
127
type: 'email'
128
},
129
validators: {
130
required: {
131
validation: Validators.required,
132
message: 'Email is required'
133
},
134
email: {
135
validation: Validators.email,
136
message: 'Please enter a valid email address'
137
},
138
custom: {
139
validation: (control: AbstractControl) => {
140
return control.value && control.value.includes('@company.com')
141
? null
142
: { customDomain: true };
143
},
144
message: 'Email must be from company domain'
145
}
146
}
147
};
148
```
149
150
### Built-in Template Validators
151
152
Template-based validation using the `formlyAttributes` directive.
153
154
```typescript { .api }
155
/**
156
* Built-in validation attributes that can be applied via props
157
*/
158
interface ValidationProps {
159
/** Field is required */
160
required?: boolean;
161
162
/** Minimum length for text inputs */
163
minLength?: number;
164
165
/** Maximum length for text inputs */
166
maxLength?: number;
167
168
/** Minimum value for numeric inputs */
169
min?: number;
170
171
/** Maximum value for numeric inputs */
172
max?: number;
173
174
/** Pattern for validation */
175
pattern?: string | RegExp;
176
177
/** Email validation */
178
email?: boolean;
179
}
180
```
181
182
**Usage Example:**
183
184
```typescript
185
const fields: FormlyFieldConfig[] = [
186
{
187
key: 'username',
188
type: 'input',
189
props: {
190
label: 'Username',
191
required: true,
192
minLength: 3,
193
maxLength: 20,
194
pattern: /^[a-zA-Z0-9_]+$/
195
}
196
},
197
{
198
key: 'age',
199
type: 'input',
200
props: {
201
label: 'Age',
202
type: 'number',
203
required: true,
204
min: 18,
205
max: 100
206
}
207
}
208
];
209
```
210
211
### Legacy Validation Components
212
213
Legacy versions of validation components for backward compatibility.
214
215
```typescript { .api }
216
/**
217
* Legacy version of FormlyValidationMessage for backward compatibility
218
* @deprecated Use FormlyValidationMessage instead
219
*/
220
@Component({ selector: 'formly-validation-message' })
221
export class LegacyFormlyValidationMessage extends FormlyValidationMessage {}
222
223
/**
224
* Legacy version of FormlyAttributes for backward compatibility
225
* @deprecated Use FormlyAttributes instead
226
*/
227
@Directive({ selector: '[formlyAttributes]' })
228
export class LegacyFormlyAttributes extends FormlyAttributes {}
229
```
230
231
## Types
232
233
### Validation Types
234
235
```typescript { .api }
236
interface ValidatorOption {
237
/** Unique name for the validator */
238
name: string;
239
240
/** Validator function (sync or async) */
241
validation: ValidatorFn | AsyncValidatorFn;
242
243
/** Additional options for the validator */
244
options?: { [id: string]: any };
245
}
246
247
interface ValidationMessageOption {
248
/** Validator name this message applies to */
249
name: string;
250
251
/** Message string or function returning message */
252
message: string | ((error: any, field: FormlyFieldConfig) => string);
253
}
254
255
interface FormlyFieldConfigValidators {
256
/** Custom validators for the field */
257
[key: string]: FormlyValidatorConfig | ValidatorFn | AsyncValidatorFn;
258
}
259
260
interface FormlyValidatorConfig {
261
/** The validator function */
262
validation: ValidatorFn | AsyncValidatorFn;
263
264
/** Options passed to the validator */
265
options?: any;
266
267
/** Custom error message for this validator */
268
message?: string | ((error: any, field: FormlyFieldConfig) => string);
269
}
270
```
271
272
### Error Handling Types
273
274
```typescript { .api }
275
interface FormlyValidatorError {
276
/** The validator name that failed */
277
validator: string;
278
279
/** Error details from the validator */
280
error: any;
281
282
/** The field that has the error */
283
field: FormlyFieldConfig;
284
285
/** Custom error message */
286
message?: string;
287
}
288
289
interface FormlyValidationErrors {
290
[validatorName: string]: any;
291
}
292
```
293
294
### Validation Expression Types
295
296
```typescript { .api }
297
type ValidatorExpression = string | ((field: FormlyFieldConfig) => boolean) | Observable<boolean>;
298
299
interface ValidatorExpressions {
300
[validatorName: string]: ValidatorExpression;
301
}
302
```
303
304
## Validation Examples
305
306
### Custom Async Validator
307
308
```typescript
309
import { AbstractControl, AsyncValidatorFn } from '@angular/forms';
310
import { Observable, of, timer } from 'rxjs';
311
import { map, switchMap } from 'rxjs/operators';
312
313
function uniqueUsernameValidator(): AsyncValidatorFn {
314
return (control: AbstractControl): Observable<any> => {
315
if (!control.value) {
316
return of(null);
317
}
318
319
return timer(300).pipe(
320
switchMap(() => {
321
// Simulate API call
322
const takenUsernames = ['admin', 'user', 'test'];
323
const isTaken = takenUsernames.includes(control.value.toLowerCase());
324
return of(isTaken ? { usernameTaken: true } : null);
325
})
326
);
327
};
328
}
329
330
// Usage in field configuration
331
const fieldConfig: FormlyFieldConfig = {
332
key: 'username',
333
type: 'input',
334
props: {
335
label: 'Username',
336
required: true
337
},
338
asyncValidators: {
339
uniqueUsername: {
340
validation: uniqueUsernameValidator(),
341
message: 'This username is already taken'
342
}
343
}
344
};
345
```
346
347
### Cross-Field Validation
348
349
```typescript
350
import { FormGroup } from '@angular/forms';
351
352
function passwordMatchValidator(control: AbstractControl) {
353
const formGroup = control.parent as FormGroup;
354
355
if (!formGroup) {
356
return null;
357
}
358
359
const password = formGroup.get('password')?.value;
360
const confirmPassword = control.value;
361
362
return password === confirmPassword ? null : { passwordMismatch: true };
363
}
364
365
const fields: FormlyFieldConfig[] = [
366
{
367
key: 'password',
368
type: 'input',
369
props: {
370
label: 'Password',
371
type: 'password',
372
required: true,
373
minLength: 8
374
}
375
},
376
{
377
key: 'confirmPassword',
378
type: 'input',
379
props: {
380
label: 'Confirm Password',
381
type: 'password',
382
required: true
383
},
384
validators: {
385
passwordMatch: {
386
validation: passwordMatchValidator,
387
message: 'Passwords must match'
388
}
389
}
390
}
391
];
392
```