Last active
July 11, 2023 20:12
-
-
Save jhades/b179cbd8b6e28fa227b6e4e4231538df to your computer and use it in GitHub Desktop.
Angular Custom Form Validators: Complete Guide - https://blog.angular-university.io/angular-custom-validators/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
User Login Form: | |
<form [formGroup]="form"> | |
<input matInput type="email" name="email" | |
placeholder="Email" formControlName="email"> | |
<input matInput type="password" | |
placeholder="Password" formControlName="password"> | |
<button [disabled]="!form.valid"> | |
Login | |
</button> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component({ | |
selector: 'login', | |
templateUrl: './login.component.html', | |
styleUrls: ['./login.component.css'] | |
}) | |
export class LoginComponent { | |
form = this.fb.group({ | |
email: ['', { | |
validators: [ | |
Validators.required, | |
Validators.email | |
], | |
updateOn: 'blur' | |
}], | |
password: [ | |
'', | |
[Validators.required, Validators.minLength(8), | |
createPasswordStrengthValidator() | |
] | |
] | |
}); | |
constructor(private fb: FormBuilder) {} | |
get email() { | |
return this.form.controls['email']; | |
} | |
get password() { | |
return this.form.controls['password']; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form = this.fb.group({ | |
password: [ | |
<form initial value>, | |
[ ... array of synchronous validators ...] | |
] | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form = this.fb.group({ | |
email: ['', { | |
validators: [ ... array of synchronous validators ...], | |
asyncValidators: [ ... array of asynchronous validators ...] | |
updateOn: 'change' or 'blur' or 'submit' | |
}], | |
... | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms'; | |
export function createPasswordStrengthValidator(): ValidatorFn { | |
return (control:AbstractControl) : ValidationErrors | null => { | |
const value = control.value; | |
if (!value) { | |
return null; | |
} | |
const hasUpperCase = /[A-Z]+/.test(value); | |
const hasLowerCase = /[a-z]+/.test(value); | |
const hasNumeric = /[0-9]+/.test(value); | |
const passwordValid = hasUpperCase && hasLowerCase && hasNumeric; | |
return !passwordValid ? {passwordStrength:true}: null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
passwordStrength: { | |
hasUpperCase: true, | |
hasLowerCase: true, | |
hasNumeric: false | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form = this.fb.group({ | |
email: ... | |
password: [ | |
'', | |
[ | |
Validators.required, | |
Validators.minLength(8), | |
createPasswordStrengthValidator() | |
] | |
] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<form #loginForm="ngForm" (ngSubmit)="login(loginForm, $event)"> | |
<input matInput type="email" name="email" | |
ngModel | |
#email="ngModel" | |
required email minlength="3" maxlength="20" | |
placeholder="Email"> | |
<input matInput type="password" name="password" | |
required passwordStrength minlength="8" | |
ngModel #password="ngModel" | |
placeholder="Password"> | |
</mat-form-field> | |
<button type="submit" [disabled]="!loginForm.valid"> | |
Login | |
</button> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Directive} from '@angular/core'; | |
import {AbstractControl, NG_VALIDATORS, ValidationErrors, Validator} from '@angular/forms'; | |
import {createPasswordStrengthValidator} from '../validators/password-strength.validator'; | |
@Directive({ | |
selector: "[passwordStrength]", | |
providers: [{ | |
provide: NG_VALIDATORS, | |
useExisting:PasswordStrengthDirective, | |
multi: true | |
}] | |
}) | |
export class PasswordStrengthDirective implements Validator { | |
validate(control: AbstractControl): ValidationErrors | null { | |
return createPasswordStrengthValidator()(control); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<input matInput type="password" | |
placeholder="Password" formControlName="password"> | |
<div class="field-message" *ngIf="password.errors?.passwordStrength"> | |
Your password must have lower case, upper case and numeric characters. | |
</div> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<form [formGroup]="form"> | |
<input placeholder="Start date" formControlName="startAt"> | |
<input placeholder="End date" formControlName="endAt"> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {FormGroup, ValidatorFn, Validators} from '@angular/forms'; | |
export function creatDateRangeValidator(): ValidatorFn { | |
return (form: FormGroup): ValidationErrors | null => { | |
const start:Date = form.get("startAt").value; | |
const end:Date = form.get("endAt").value; | |
if (start && end) { | |
const isRangeValid = (end.getTime() - start.getTime() > 0); | |
return isRangeValid ? null : {dateRange:true}; | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form = this.fb.group({ | |
startAt: [null, Validators.required], | |
endAt: [null, Validators.required] | |
}, { | |
validators: [createDateRangeValidator()] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Create User Form: | |
<form [formGroup]="form"> | |
<input matInput type="email" name="email" | |
placeholder="Enter the new user email" formControlName="email" #email> | |
<div class='field-message' *ngIf="email?.errors.userExists"> | |
An user with email {{email.value}} already exists. | |
</div> | |
<input matInput type="password" | |
placeholder="Password" formControlName="password"> | |
<input matInput type="password" | |
placeholder="Confirm Password" formControlName="confirmPassword"> | |
<button [disabled]="!form.valid"> | |
Create User | |
</button> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component({ | |
selector: 'login', | |
templateUrl: './create-user.component.html', | |
styleUrls: ['./create-user.component.css'] | |
}) | |
export class CreateUserComponent { | |
form = this.fb.group({ | |
email: ['', { | |
validators: [ | |
Validators.required, | |
Validators.email | |
], | |
asyncValidators: [userExistsValidator(this.user)] | |
updateOn: 'blur' | |
}], | |
.... | |
}); | |
constructor(private fb: FormBuilder, private user: UserService) {} | |
get email() { | |
return this.form.controls['email']; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {AbstractControl, AsyncValidatorFn} from '@angular/forms'; | |
export function userExistsValidator(user: UserService):AsyncValidatorFn { | |
return (control: AbstractControl) => { | |
return user.findUserByEmail(control.value) | |
.pipe( | |
map(user => user ? {userExists:true} : null) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment