Core package of ngx-formly - a dynamic (JSON powered) form library for Angular that brings unmatched maintainability to your application's forms
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Validation system with custom validators, validation messages, and error handling components for comprehensive form validation.
Component for displaying validation error messages with customizable message rendering.
/**
* Component for displaying field validation messages
*/
@Component({
selector: 'formly-validation-message',
template: `<div class="error-message">{{ errorMessage }}</div>`
})
export class FormlyValidationMessage implements OnInit {
/** The field configuration containing validation state */
@Input() field: FormlyFieldConfig;
/** The current error message to display */
errorMessage: string;
}Usage Example:
@Component({
template: `
<div class="form-field">
<input [formControl]="formControl" [formlyAttributes]="field">
<formly-validation-message
*ngIf="showError"
[field]="field">
</formly-validation-message>
</div>
`
})
export class CustomFieldComponent extends FieldType {
get showError() {
return this.field.showError && this.formControl.invalid;
}
}Directive for applying field attributes and handling focus, blur, and change events.
/**
* Directive for applying field attributes and event handling
*/
@Directive({
selector: '[formlyAttributes]',
host: {
'(focus)': 'onFocus($event)',
'(blur)': 'onBlur($event)',
'(change)': 'onChange($event)',
}
})
export class FormlyAttributes implements OnInit, DoCheck {
/** The field configuration */
@Input('formlyAttributes') field: FormlyFieldConfig;
/** Focus event handler */
onFocus(event: Event): void;
/** Blur event handler */
onBlur(event: Event): void;
/** Change event handler */
onChange(event: Event): void;
}Usage Example:
@Component({
template: `
<input
[formControl]="formControl"
[formlyAttributes]="field"
[placeholder]="props.placeholder"
[disabled]="props.disabled">
`
})
export class InputFieldComponent extends FieldType {}Field-level validation configuration supporting both sync and async validators.
/**
* Validation configuration for individual fields
*/
interface FormlyFieldConfigValidators {
[key: string]: FormlyValidatorConfig | ValidatorFn | AsyncValidatorFn;
}
interface FormlyValidatorConfig {
/** The validator function */
validation: ValidatorFn | AsyncValidatorFn;
/** Options passed to the validator */
options?: any;
/** Custom error message for this validator */
message?: string | ((error: any, field: FormlyFieldConfig) => string);
}Usage Example:
const fieldConfig: FormlyFieldConfig = {
key: 'email',
type: 'input',
props: {
label: 'Email Address',
required: true,
type: 'email'
},
validators: {
required: {
validation: Validators.required,
message: 'Email is required'
},
email: {
validation: Validators.email,
message: 'Please enter a valid email address'
},
custom: {
validation: (control: AbstractControl) => {
return control.value && control.value.includes('@company.com')
? null
: { customDomain: true };
},
message: 'Email must be from company domain'
}
}
};Template-based validation using the formlyAttributes directive.
/**
* Built-in validation attributes that can be applied via props
*/
interface ValidationProps {
/** Field is required */
required?: boolean;
/** Minimum length for text inputs */
minLength?: number;
/** Maximum length for text inputs */
maxLength?: number;
/** Minimum value for numeric inputs */
min?: number;
/** Maximum value for numeric inputs */
max?: number;
/** Pattern for validation */
pattern?: string | RegExp;
/** Email validation */
email?: boolean;
}Usage Example:
const fields: FormlyFieldConfig[] = [
{
key: 'username',
type: 'input',
props: {
label: 'Username',
required: true,
minLength: 3,
maxLength: 20,
pattern: /^[a-zA-Z0-9_]+$/
}
},
{
key: 'age',
type: 'input',
props: {
label: 'Age',
type: 'number',
required: true,
min: 18,
max: 100
}
}
];Legacy versions of validation components for backward compatibility.
/**
* Legacy version of FormlyValidationMessage for backward compatibility
* @deprecated Use FormlyValidationMessage instead
*/
@Component({ selector: 'formly-validation-message' })
export class LegacyFormlyValidationMessage extends FormlyValidationMessage {}
/**
* Legacy version of FormlyAttributes for backward compatibility
* @deprecated Use FormlyAttributes instead
*/
@Directive({ selector: '[formlyAttributes]' })
export class LegacyFormlyAttributes extends FormlyAttributes {}interface ValidatorOption {
/** Unique name for the validator */
name: string;
/** Validator function (sync or async) */
validation: ValidatorFn | AsyncValidatorFn;
/** Additional options for the validator */
options?: { [id: string]: any };
}
interface ValidationMessageOption {
/** Validator name this message applies to */
name: string;
/** Message string or function returning message */
message: string | ((error: any, field: FormlyFieldConfig) => string);
}
interface FormlyFieldConfigValidators {
/** Custom validators for the field */
[key: string]: FormlyValidatorConfig | ValidatorFn | AsyncValidatorFn;
}
interface FormlyValidatorConfig {
/** The validator function */
validation: ValidatorFn | AsyncValidatorFn;
/** Options passed to the validator */
options?: any;
/** Custom error message for this validator */
message?: string | ((error: any, field: FormlyFieldConfig) => string);
}interface FormlyValidatorError {
/** The validator name that failed */
validator: string;
/** Error details from the validator */
error: any;
/** The field that has the error */
field: FormlyFieldConfig;
/** Custom error message */
message?: string;
}
interface FormlyValidationErrors {
[validatorName: string]: any;
}type ValidatorExpression = string | ((field: FormlyFieldConfig) => boolean) | Observable<boolean>;
interface ValidatorExpressions {
[validatorName: string]: ValidatorExpression;
}import { AbstractControl, AsyncValidatorFn } from '@angular/forms';
import { Observable, of, timer } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
function uniqueUsernameValidator(): AsyncValidatorFn {
return (control: AbstractControl): Observable<any> => {
if (!control.value) {
return of(null);
}
return timer(300).pipe(
switchMap(() => {
// Simulate API call
const takenUsernames = ['admin', 'user', 'test'];
const isTaken = takenUsernames.includes(control.value.toLowerCase());
return of(isTaken ? { usernameTaken: true } : null);
})
);
};
}
// Usage in field configuration
const fieldConfig: FormlyFieldConfig = {
key: 'username',
type: 'input',
props: {
label: 'Username',
required: true
},
asyncValidators: {
uniqueUsername: {
validation: uniqueUsernameValidator(),
message: 'This username is already taken'
}
}
};import { FormGroup } from '@angular/forms';
function passwordMatchValidator(control: AbstractControl) {
const formGroup = control.parent as FormGroup;
if (!formGroup) {
return null;
}
const password = formGroup.get('password')?.value;
const confirmPassword = control.value;
return password === confirmPassword ? null : { passwordMismatch: true };
}
const fields: FormlyFieldConfig[] = [
{
key: 'password',
type: 'input',
props: {
label: 'Password',
type: 'password',
required: true,
minLength: 8
}
},
{
key: 'confirmPassword',
type: 'input',
props: {
label: 'Confirm Password',
type: 'password',
required: true
},
validators: {
passwordMatch: {
validation: passwordMatchValidator,
message: 'Passwords must match'
}
}
}
];