I want the Nehal solution to work, but I could not do it. Came with my solution after working with @ AJT_82 code. My need really was that you wanted to check the passwords as a group, and his solution did not cover it. So, I included other things that I used to create a complete solution that worked for me.
I ran into this problem while trying to do a password confirmation check in angular 4 after finding that the method I used in 2 didn't work anymore. The information about angular.io actually did not help much, since most of the information is fragmented in different areas of their documentation.
So, to clarify, this follows the angular reactive form method. I wrote this to verify passwords in an instance where I also had other verification restrictions (password must be between 4 and 24 characters, required, etc.). This method should work just as well for email confirmation with a few small tweaks.
First, to compare validators for a group, the html form must have a subgroup identified using the identifier formGroupName = "". This is in the main identifier of [formGroup]. Composite input must be inside this element labeled formGroupName. In my case, it's just a div.
<div class="title">Hero Registration Form</div> <form [formGroup]="regForm" id="regForm" (ngSubmit)="onSubmit()"> <div class="input"> <label for="heroname">Heroname</label> <input type="text" id="heroname" class="form-control" formControlName="heroname" required /> <div *ngIf="formErrors.heroname" class="hero-reg-alert">{{ formErrors.heroname }}</div> </div> <div class="input"> <label for="email">Email</label> <input type="email" id="email" class="form-control" formControlName="email" required /> <div *ngIf="formErrors.email" class="hero-reg-alert">{{ formErrors.email }}</div> </div> <div formGroupName="password"> <div class="input"> <label for="password1">Password</label> <input type="password" id="password1" class="form-control" formControlName="password1" required /> <div *ngIf="formErrors.password.password1" class="hero-reg-alert"> {{ formErrors.password.password1 }}</div> </div> <div class="input"> <label for="password2">Re-Enter Password</label> <input type="password" id="password2" class="form-control" formControlName="password2" required /> <div *ngIf="formErrors.password.password2 || formErrors.password.password" class="hero-reg-alert">{{ formErrors.password.password }} {{ formErrors.password.password2 }}</div> </div> </div> <button type="submit" [disabled]="!regForm.valid"> <span id="right-btntxt">SUBMIT</span> </button> </form>
You may notice that I have values ββfor formErrors as
formErrors.password.password formErrors.password.password1 formErrors.password.password2
They are embedded in my code so ...
formErrors = { 'username': '', 'email': '', 'password': { 'password': '', 'password1': '', 'password2': '' } };
I built it in such a way that "password1" and "password2" save my Errors form for each field, and "password" contains my error in case of inconsistency (where the two entered passwords are not equal).
There could be an onValueChanged () formula. It checks if the field is an instance of FormGroup. If so, he first checks the user check for this group of fields (storing them in 'this.formErrors [field] [field]'), then proceeds to processing the subfields. In case it is not an instance of FieldGroup, the check is performed according to the example in the angular.io guideance doc.
onValueChanged(data?: any) { if (!this.regForm) {return;} const form = this.regForm; for (const field in this.formErrors) { const formControl = form.get(field); if (formControl instanceof FormGroup) { this.formErrors[field][field] = ''; // check for custom validation on field group const control = form.get(field); // handle validation for field group if (control && control.dirty && !control.valid) { const messages = this.validationMessages[field]; for (const key in control.errors) { this.formErrors[field][field] += messages[key] + ' '; } } // handle validation for subfields for (const subfield in formControl.controls) { console.log('SUBFIELD', subfield); this.formErrors[field][subfield] = ''; const control = formControl.controls[subfield]; if (control && control.dirty && !control.valid) { const messages = this.validationMessages[subfield]; for (const key in control.errors) { this.formErrors[field][subfield] += messages[key] + ' '; } } } } // alternate validation handling for fields without subfields (AKA not in a group) else { const control = form.get(field); this.formErrors[field] = ''; if (control && control.dirty && !control.valid) { const messages = this.validationMessages[field]; for (const key in control.errors) { this.formErrors[field] += messages[key] + ' '; } } } } }
By providing the FieldGroup with a subfield with its own name, we can store checks in the FieldGroup. Trying to do this with the usual onValueChange code overwrites the subfield in the line ...
this.formErrors[field] = '';
Not providing storage space for the FieldGroup check either overwrites the subfield or does not process the FieldGroup.
If you need it, this is how the form is created using buildFomr ();
buildForm(): void { this.regForm = this.formBuilder.group({ 'username': [this.registerUser.username, [ Validators.required, Validators.minLength(4), Validators.maxLength(24) ] ], 'email': [this.registerUser.email, [ Validators.email, Validators.required ] ], 'password': this.formBuilder.group({ 'password1': [this.registerUser.password, [ Validators.required, Validators.minLength(8), Validators.maxLength(24) ] ], 'password2': ['', [ Validators.required ] ] }, {validator: this.passwordMatchValidator}) });
and this is a special check function ...
passwordMatchValidator(control: FormGroup): {[key: string]: any} { return control.get('password1').value !== control.get('password2').value ? {mismatch: true} : null; }