1

I know there is a lot of topics about the same subject on the web but I can't manage to find the solution that works for me.

I have a form make with the formBuilder of angular, it's a profile form in which we can change the password, so we have three password input: the old one, the new one, and a confirmation for the new password.

Here is the form :

this.editProfileForm = this.formBuilder.group({
  lastname: ['', Validators.required],
  firstname: ['', Validators.required],
  email: ['', [Validators.required, Validators.email]],
  phone: [this.phone.replace(/\s/g, ''), [Validators.pattern('[0-9]{10}')]],
  birthdate: ['', [Validators.required]],
  password: [''],
  new_password: [''],
  new_password_confirm: [''],
});
this.editProfileForm.setValidators([this.ageValidator, this.samePasswordValidator, this.requiredPasswordValidator]);

What I try to do is to make the passwords fields required only if one of them is not empty. If the user start typing in one of the passwords fields then the three are required.

Here is what I try :

public requiredPasswordValidator(form: FormGroup): any {
  if (form.controls.password.value || form.controls.new_password.value || form.controls.new_password_confirm.value) {

    form.controls.password.setValidators([Validators.required]);
    form.controls.new_password.setValidators([Validators.required, Validators.minLength(6)]);
    form.controls.new_password_confirm.setValidators([Validators.required, Validators.minLength(6)]);
  }
}

It seems works but not perfectly, the fields became required only if I start typing on it and erase, and this for each fields. For example if I type in password field, the new and new_confirm are not required, but if I type a random letter in the new pw input and remove it then the field is required.

I don't know if my explications are really clear, if you need more ask me.

Thanks.

Edit

I tried with Ankur Jain solution but still have the same problem :

Here is the function :

public formControlValueChanged(): void {
    this.editProfileForm.get('password').valueChanges.subscribe(
      (mode: string) => {
        if (mode) {
          this.f.new_password.setValidators([Validators.required]);
          this.f.new_password_confirm.setValidators([Validators.required]);
        }
      });
  }

(I use this.f because with juste new_password & new_password confirm it throw an error, the this.f is a function that return editProfileForm.controls)

And I call it in ngOninit :

  this.formControlValueChanged();

I also try to add this.editProfileForm.updateValueAndValidity(); to the function but this change nothing.

Jess
  • 21
  • 5
  • Why not try to make a custom validator over all the formGroup that can return an array of three objects (some of then can be null)? – Eliseo Feb 11 '19 at 15:08

3 Answers3

0

Try to do this after calling setValidators():

form.controls.password.updateValueAndValidity();
form.controls.new_password.updateValueAndValidity();
form.controls.new_password_confirm.updateValueAndValidity();

According to the documentation, updateValueAndValidity:

Recalculates the value and validation status of the control.

XardasLord
  • 1,764
  • 2
  • 20
  • 45
  • I was trying to do `form.updateValueAndValidity(); ` and with this or your answer I got an error "Maximum call stack size exceeded", I think because the form is updated so the validator is called again, and the form updated again, etc ... – Jess Feb 11 '19 at 13:51
  • @Jess Doesn't this solution fits to you? -> https://stackoverflow.com/questions/51605737/confirm-password-validation-in-angular-6 – XardasLord Feb 11 '19 at 13:57
  • This solution seems to just show an error message if the password input is touched, I want to add the required validator to my fields if one is not empty, and remove the validator if they are empty – Jess Feb 11 '19 at 14:06
0

You can subscribe for the value change event of the form.

formControlValueChanged() {
    this.editProfileForm.get('password').valueChanges.subscribe(
       (mode: string) => {
           if(mode){ 
               new_password.setValidators([Validators.required]);
               new_password_confirm.setValidators([Validators.required]);
            }
        });
}

in ngOnInit:

ngOnInit() {
    this.formControlValueChanged();
}
Ankur Jain
  • 221
  • 1
  • 6
  • I'm trying with your solution but I got the same problem, the validator is 'activated' only if I enter something in the field and erase it. – Jess Feb 11 '19 at 13:54
0

From what I understand you want to set required for all if there is some value in one of the fields, if not, they are not required. Therefore, let's just check that, and if there is value in one of the fields, set an error on the form... for example { allRequired: true }. If there is values in all controls, return null.

passwordsValidator(form: FormGroup): any {
  const ctrls = form.controls;
  if (ctrls.password.value && ctrls.new_password.value && ctrls.new_password_confirm.value) {
    return null;
  } else if (ctrls.password.value || ctrls.new_password.value || ctrls.new_password_confirm.value) {
    return { allRequired: true}
  }
  return null;
}

Then we can just show the error in template using hasError:

<p *ngIf="editProfileForm.hasError('allRequired')">Password fields are required!</p>

Here's a StackBlitz

AT82
  • 71,416
  • 24
  • 140
  • 167
  • I have tried a solution like this, the problem is that when the three inputs have a value the error still on the form, so he's not valid – Jess Feb 12 '19 at 08:10
  • @Jess Oh, sorry, I must have been tired yesterday :D It's fixed now, and should work as you wish :) – AT82 Feb 12 '19 at 09:42
  • I think i have a problem on my side because my errors message doesn't show up directly when I start typing on a field, but your solution seems good – Jess Feb 12 '19 at 10:01
  • Could you fork and try to replicate your issue in the StackBlitz I made, and I'd be happy to take a look :) – AT82 Feb 12 '19 at 10:03
  • It works (I just forgot a condition on my html), thanks – Jess Feb 12 '19 at 10:06