-
Notifications
You must be signed in to change notification settings - Fork 79
/
special-validators.ts
135 lines (121 loc) · 4.99 KB
/
special-validators.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { FormControl, FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
/**
* A helper function that transforms the special validators to a formly-usable function.
*
* @param name the error to be extracted from the validator
* @param validator the validator that should be transformed
* @returns a function that conforms the type signature formly expects.
*
* @usageNotes
* Refer to the [`FormlyFieldConfig.validators`](https://github.com/ngx-formly/ngx-formly/blob/main/src/core/src/lib/models/fieldconfig.ts#L60) type definition for an explanation of the necessary validator format.
*
*/
export function formlyValidation<T extends (control: FormControl) => { [error: string]: { valid: boolean } }>(
name: string,
validator: T
): (control: FormControl) => boolean {
return c => {
const validationResult = validator(c);
if (!c) {
return;
}
return validationResult?.[name]?.valid ?? true;
};
}
export class SpecialValidators {
/**
* password validator: char + numbers, min length 7
*/
static password(control: FormControl): { [error: string]: { valid: boolean } } {
const passwordPattern = /^(|(?=[^\s]*[a-zA-Z])(?=[^\s]*[\d])[^\s]*)$/;
if (!control.value) {
return;
}
return passwordPattern.test(control.value) && control.value.length > 6 ? undefined : { password: { valid: false } };
}
static noSpecialChars(control: FormControl): { [error: string]: { valid: boolean } } {
const noSpecialCharsPattern = /^[^\<\>\&\@\;\%\*\#\|\_\[\]\!\?\~\+\{\}\(\)\:]*$/;
return noSpecialCharsPattern.test(control.value) ? undefined : { noSpecialChars: { valid: false } };
}
static punchoutLogin(control: FormControl): { [error: string]: { valid: boolean } } {
const punchoutLoginPattern = /^[a-zA-Z0-9_.@]*$/;
return punchoutLoginPattern.test(control.value) ? undefined : { punchoutLogin: { valid: false } };
}
static integer(control: FormControl): { [error: string]: { valid: boolean } } {
const integerPattern = /^(?:-?(?:0|[1-9][0-9]*)|)$/;
return integerPattern.test(control.value) ? undefined : { integer: { valid: false } };
}
static email(control: FormControl): { [error: string]: { valid: boolean } } {
/*
* very simplified email matching
* - local part mustn't start or end with dot
* - domain mustn't start or end with dash
* - no IPs allowed for login emails
* - only some special characters allowed
*/
return /^([\w\-\~\+]+\.)*[\w\-\~\+]+@(([\w][\w\-]*)?[\w]\.)+[a-zA-Z]{2,}$/.test(control.value)
? undefined
: { email: { valid: false } };
}
static phone(control: FormControl): { [error: string]: { valid: boolean } } {
/*
* simplified phone matching
* - phone number must start with + or digit
* - number blocks can be separated with hyphens or spaces
* - number blocks can stand in brackets
* - phone number must have 7 to 15 digits
*/
return control.value
? /^((?:\+?\d{7,15})$)|^((\(?\d{3}\)?(?: |-)?){2}\(?\d{3,4}\)?)$/.test(control.value)
? undefined
: { phone: { valid: false } }
: undefined;
}
/**
* Compare two form controls for equality.
*
* The Validator has to be attached to the parent form group containing both controls under investigation.
* The first argument control name receives the error if controls do not have an equal value.
*/
static equalTo(errorReceivingControlName: string, compareControlName: string): ValidatorFn {
return (group: FormGroup): ValidationErrors => {
const errorReceivingControl = group.get(errorReceivingControlName);
const otherErrorKeys = Object.keys(errorReceivingControl?.errors || {}).filter(x => x !== 'equalTo');
if (errorReceivingControl && !otherErrorKeys.length) {
errorReceivingControl.setErrors(
errorReceivingControl.value === group.get(compareControlName)?.value
? undefined
: { equalTo: { valid: false } }
);
}
return [];
};
}
static equalToControl(otherControlName: string): ValidatorFn {
return (control: FormControl) => {
const otherControl = control.parent?.get(otherControlName);
if (otherControl && otherControl.value !== control.value) {
return {
equalTo: { valid: false },
};
}
};
}
static moneyAmount(control: FormControl): { [error: string]: { valid: boolean } } {
const moneyAmountPattern = /^$|^\d{1,9}(\.\d{1,2})?$/;
if (!control.value) {
return;
}
return moneyAmountPattern.test(control.value) ? undefined : { moneyAmount: { valid: false } };
}
static noSunday(control: FormControl): boolean {
return SpecialValidators.noDay(control, 'sunday');
}
static noSaturday(control: FormControl): boolean {
return SpecialValidators.noDay(control, 'saturday');
}
private static noDay(control: FormControl, day: 'saturday' | 'sunday'): boolean {
const date = control.value as Date;
return !(day === 'saturday' ? date?.getDay() === 6 : date?.getDate() === 0);
}
}