I am in the process of developing a material password confirmation component that can be seamlessly integrated with Angular Reactive Forms. This will allow the same component to be utilized in both Registration and Password Reset forms.
If you would like to see a working example, I have created a self-contained Stackblitz Demo here. In this demo, the password field has validation constraints for minimum and maximum length, and the confirm password field is marked as required.
The submit button on the form will remain disabled until all validation requirements are met and the passwords match successfully.
In order to integrate this component into Angular Material Reactive Forms, it was necessary to follow guidelines outlined in this article. Specifically, the control had to implement the ControlValueAccessor
interface and the Validator
interface, which have been duly implemented and showcased in this demonstration.
A snapshot of the form structure is provided below:
<mat-card class="PasswordFormTestCard">
<form class="RegistrationForm" [formGroup]="form" (ngSubmit)="submit()">
<mat-form-field>
<input
matInput
placeholder="username"
type="text"
formControlName="username"
/>
<mat-hint *ngIf="!username">Example Monica</mat-hint>
<mat-error>Please enter your username</mat-error>
</mat-form-field>
<fs-password-form formControlName="password"></fs-password-form>
<button mat-button type="submit" [disabled]="!form.valid">Submit</button>
</form>
</mat-card>
The custom password form control is bound within the form using the following syntax:
<fs-password-form formControlName="password"></fs-password-form>
While the setup appears to "almost" function correctly, there is an issue with the submit button becoming enabled as soon as characters are entered into the confirmPassword field. The validate
function should ideally prevent this behavior, but currently does not. The implementation of the function is shown below:
//=============================================
// Validator API Methods
//=============================================
validate(control: AbstractControl): ValidationErrors | null {
if (
this.passwordForm.valid &&
this.confirmPasswordControl.valid &&
this.passwordControl.valid
) {
console.log('BOTH THE FORM AND THE CONTROLS ARE VALID');
return null;
}
let errors: any = {};
errors = this.addControlErrors(errors, 'password');
errors = this.addControlErrors(errors, 'confirmPassword');
return errors;
}
addControlErrors(allErrors: any, controlName: string) {
const errors = { ...allErrors };
const controlErrors = this.passwordForm.controls[controlName].errors;
if (controlErrors) {
errors[controlName] = controlErrors;
}
return errors;
}
Although the function is designed to only return null when both the form and controls are valid, it seems to be returning null prematurely. If anyone has suggestions or insights on why this might be occurring, please feel free to share.