Create a form for changing a password
Verify same password in both inputs
Apply error displays, according to case
Toggle password visibility
1. Component - HTML
<div class="password-reset">
<form
role="form"
(ngSubmit)="submit()"
[formGroup]="changePasswordForm"
autocomplete="off"
>
<div fxLayout="column" fxLayoutAlign="space-between" fxLayoutGap="5.7vw">
<div>
<mat-form-field hideRequiredMarker class="full-width">
<mat-label>Password</mat-label>
<input
matInput
name="password"
id="password"
formControlName="password"
[type]="hidePassword ? 'password' : 'text'"
>
<mat-error *ngIf="doShowHintsForCorrectPassword()">
{{ doDisplayHintsForCorrectPassword() }}
</mat-error>
<button
type="button"
mat-icon-button
matSuffix
(click)="hidePassword = !hidePassword"
>
<mat-icon>{{ hidePassword ? 'visibility_off' : 'visibility' }}</mat-icon>
</button>
</mat-form-field>
</div>
<div>
<mat-form-field hideRequiredMarker class="full-width">
<mat-label>Confirm Password</mat-label>
<input
matInput
name="confirmPassword"
id="confirmPassword"
formControlName="confirmPassword"
[type]="hideConfirmPassword ? 'password' : 'text'"
>
<mat-error *ngIf="changePasswordForm.get('confirmPassword')?.errors?.sameValue">
Confirm password error
</mat-error>
<button
type="button"
mat-icon-button
matSuffix
(click)="hideConfirmPassword = !hideConfirmPassword"
>
<mat-icon>{{ hideConfirmPassword ? 'visibility_off' : 'visibility' }}</mat-icon>
</button>
</mat-form-field>
</div>
<br>
</div>
<div fxLayoutAlign="space-between" fxLayoutGap="2.7vw">
<div fxFlex="50%">
<button
type="submit"
mat-raised-button
class="full-width"
[disabled]="!changePasswordForm.valid"
>
Save
</button>
</div>
<div fxFlex="50%">
<button type="button" mat-raised-button class="full-width">
Cancel
</button>
</div>
</div>
</form>
</div>
2. Component - TS
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { register } from '../shared/util/component-mapping';
export class TestCompComponent implements OnInit {
public static COMPONENT_NAME = 'TestCompComponent';
changePasswordForm = this.fb.group({
password: ['', [Validators.required]],
confirmPassword: ['', Validators.required]
});
hidePassword = true;
hideConfirmPassword = true;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {}
submit(): void {
this.validateFormBeforeRequest();
if (!this.changePasswordForm.invalid) {
// do something
}
}
private validateFormBeforeRequest(): void {
this.changePasswordForm.controls['password'].setValidators([
Validators.required,
AppValidators.minLength(10),
AppValidators.containsCapitalLetter(),
AppValidators.containsNumber()
]);
this.changePasswordForm.controls['password'].updateValueAndValidity();
this.changePasswordForm.controls['password'].valueChanges.subscribe(() => {
this.changePasswordForm.controls['confirmPassword'].updateValueAndValidity();
});
this.changePasswordForm.controls['confirmPassword'].setValidators([
Validators.required,
AppValidators.sameValue('password')
]);
this.changePasswordForm.controls['confirmPassword'].updateValueAndValidity();
}
doShowHintsForCorrectPassword(): boolean {
const errors = this.changePasswordForm.controls['password'].errors;
if (errors && (errors.minLength || errors.containsNumber || errors.containsCapitalLetter)) {
return true;
}
return false;
}
doDisplayHintsForCorrectPassword(): string {
const errors = this.changePasswordForm.controls['password'].errors;
const error = 'Error! ';
if (errors) {
const hint1 = errors.containsNumber ? 'Should contain numbers' : '';
const hint2 = errors.containsCapitalLetter ? ', Should contain capital letter' : '';
const hint3 = errors.minLength ? ', Too short' : '';
return error + hint1 + hint2 + hint3;
} else {
return error;
}
}
}
3. Component - CSS
.full-width {
width: 100%;
}
.password-reset {
height: 100%;
padding: 2.7vw;
}
mat-form-field.mat-form-field {
font-size: 2.08vh;
line-height: 2.6vh;
}
4. app.validators.ts
import { ValidatorFn, AbstractControl } from '@angular/forms';
export class AppValidators {
private static satisfiesPattern(value: string, pattern: string): boolean {
return new RegExp(pattern).test(value);
}
static containsNumber(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const containsNumber = this.satisfiesPattern(control.value, '\\d');
return !containsNumber ? { containsNumber: { value: control.value } } : null;
};
}
static containsCapitalLetter(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const containsCapitalLetter = this.satisfiesPattern(
control.value,
'.*[A-Z].*'
);
return !containsCapitalLetter
? { containsCapitalLetter: { value: control.value } }
: null;
};
}
static minLength(minLength: number): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const notEnoughLength = control.value.length < minLength;
return notEnoughLength
? {
minLength: {
requiredLength: minLength,
actualLength: control.value.length
}
}
: null;
};
}
static sameValue(formControlName: string): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const otherFormControlValue = control.parent.controls[formControlName].value;
const notSame = control.value !== otherFormControlValue;
return notSame
? {
sameValue: {
value: control.value,
otherValue: otherFormControlValue
}
}
: null;
};
}
}
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
What may be missing, or could get better?