HTML set of password and confirm password form fields :
<mat-form-field>
<mat-label>{{ 'PAGES.LOGIN.PASSWORD' | translate }}</mat-label>
<input #registerPasswordField matInput title=" " [type]="hide ? 'password' : 'text'" [formControl]="password" required (keyup.enter)="registerConfirmField.focus()">
<button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
<mat-error *ngIf="password.invalid && password.errors?.pattern">{{ 'PAGES.REGISTER.PASSWORD_INVALID' | translate }}</mat-error>
<mat-error *ngIf="password.invalid && !password.errors?.pattern">{{ 'PAGES.LOGIN.PASSWORD_REQUIRED' | translate }}</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'PAGES.REGISTER.CONFIRM' | translate }}</mat-label>
<input #registerConfirmField matInput title=" " [type]="hide ? 'password' : 'text'" [formControl]="confirmPassword" required (keyup.enter)="loginButton.focus(); register()">
<button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
<mat-error *ngIf="confirmPassword.errors?.pattern">{{ 'PAGES.REGISTER.CONFIRM_MISMATCH' | translate }}</mat-error>
<mat-error *ngIf="confirmPassword.invalid">{{ 'PAGES.REGISTER.CONFIRM_REQUIRED' | translate }}</mat-error>
</mat-form-field>
With the following TS-side form field declarations:
password = new FormControl("", [
Validators.required,
Validators.pattern("^((?=\\S*?[A-Z])(?=\\S*?[a-z])(?=\\S*?[0-9]).{8,255})\\S$")
])
confirmPassword = new FormControl("", [
Validators.required,
confirmEquals(this, this.password) //pseudocode, obviously this won't work
])
I'm trying to do something to this effect where I simply check equals between password.value and confirmPassword.value.
I haven't been able to do this with Validators.pattern() (which I don't understand why Validators.pattern(this.password.value) doesn't work. the doc says it also accepts a string in which case it appends ^ in front and $ behind, basically it regexes for that string only. It SHOULD work. but this Validator never gets triggered)
I've seen a ton of stackoverflow issues regarding the question of password confirmation but none seem clean or succinct (but most importantly up-to-date) to me.
I found this old deprecated code example :
ngOnInit() {
this.registerForm = this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6)]],
confirmPassword: ['', Validators.required]
}, {
validator: MustMatch('password', 'confirmPassword')
});
}
which shows that at one point angular did bother to implement a function to this effect.
but so far as I can tell it hasn't been moved over to the new AbstractControl CLASS
the field "validators" exist on the new syntax of FormGroup but I prefer the newer syntax where you don't declare a whole form but simply each field, as demonstrated in the new angular-material docs.
using FormBuilder seems to be discouraged nowadays.
and I want my approach to be KISS and performant as well as syntactically succinct.
Is it at all possible to do password confirmation (in a clean, modern fashion) without chaperoning the two formControls under a common formGroup?
I'll accept that this is a bad approach but I'd like to know why and what is the "Angular 11" way of doing it (the answer needs to be up to speed with the current day best practices).
EDIT: I've been reading this :Reference - Password Validation
and the comments on this : https://stackoverflow.com/a/12806002/4770754
I'm in the situation where I have to create my own registration though.