7

I'm trying to validate a form using custom validation. For some reason I have to build a form that can change either E-Mail or set a new Password. For that reason I cannot use Validators.required as password fields become only required when they are touched.

My problem is that when input validation is resolved the form is still invalid.

I've made a plnkr to demonstrate my problem:
http://plnkr.co/edit/obF4gC5RHkXOOlCEsIuH?p=preview

ngOnInit(): void {
    this.emailField = new FormControl('[email protected]', Validators.email);
    this.pw1 = new FormControl('', [this.passwordAreEqualValidator, Validators.minLength(2)]);
    this.pw2 = new FormControl('', this.passwordAreEqualValidator);
    this.pwOld = new FormControl('', this.notEmptyIfNewIsTouchedValidator);

    this.form = this.formBuilder.group({
      pw1: this.pw1,
      pw2: this.pw2,
      emailField: this.emailField,
      pwOld: this.pwOld
    });
  }

notEmptyIfNewIsTouchedValidator(control: FormControl) : ValidationErrors | null {
    if (control.dirty) {
      if (control.value === '') {
        return {
          oldPasswordEmpty: true
        }
      }

      const parent = control.parent,
            pw1 = parent.get('pw1'),
            pw2 = parent.get('pw2');

      // this will trigger nothing in template, this part is only
      // to mark form invalid if password was entered. passwordNew1
      // cannot be false by default as this is okay when you only
      // want to change your e-mail adress.
      if (pw1.value.length === 0) {
        pw1.setErrors({noPassword: true});
      } else {
        if (pw1.hasError('noPassword')) {
          let pw1Errors = pw1.errors;
          delete pw1Errors.noPassword;  
          pw1.setErrors(pw1Errors);
        }
      }

      console.log('pw1 errors: ', pw1.errors);
      console.log('pw2 errors: ', pw2.errors);
      console.log('old errors: ', control.errors);
    }

    return null;
  }

  passwordAreEqualValidator(control: FormControl): ValidationErrors | null {
    if (control.dirty) {
      const
        parent = control.parent,
        pwOld = parent.get('pwOld'),
        pw1 = parent.get('pw1'),
        pw2 = parent.get('pw2');

      if (pwOld.value === '') {
        pwOld.setErrors({oldPasswordEmpty: true})
      }

      if (pw1.value !== pw2.value) {
        return {
          notEqual: true
        };
      } else {
        let pw1Errors = pw1.errors;

        if (pw1.hasError('notEqual')) {
          delete pw1Errors.notEqual;
          pw1.setErrors(pw1Errors);
        }

        if (pw1.hasError('noPassword')) {
          delete pw1Errors.noPassword;
          pw1.setErrors(pw1Errors);
        }

        pw2.setErrors(null);

        console.log('pw1 errors: ', pw1.errors);
        console.log('pw2 errors: ', pw2.errors);
        console.log('old errors: ', pwOld.errors);
      }
    }

    return null;
  }

Steps to reproduce:

  1. Enter a password (error old password is empty shows up)
  2. Repeat Password (error password are not equal shows up until both password matches)
  3. once your repeating password is matching add a value for old password (error old password is removed)
  4. all validation errors are removed, but still form is not valid.

Why is my form invalid?

P.S: Once I edit my pw1 again, my form becomes valid, although the result of the errors did not change.

2 Answers 2

1

You have the Validator set on both fields..... what happens is that pw1 does not revalidate when you enter pw2, so pw1 is still invalid until you go back and type it in again.

In your component, at the end of your ngOnInit, you can add the following....

    this.pw1.valueChanges().subscribe(() => this.pw2.updateValueAndValidity());
    this.pw2.valueChanges().subscribe(() => this.pw1.updateValueAndValidity());
Sign up to request clarification or add additional context in comments.

Comments

0

This answer is only related to the problem of a form that is invalid but has no errors, and not an answer to the identified problem.

I am creating subforms; my base FormGroup has both FormGroups and FormArrays as components.

this.form = this.formBuilder.group({
  name: FormControl('', []),
  addresses: this.formBuilder.array([
    this.formBuilder.group({
      street: FormControl('', []),
      city: FormControl('', []),
      state: FormControl('', []),
      zip: FormControl('', []),
    }),
    this.formBuilder.group({
      street: FormControl('', []),
      city: FormControl('', []),
      state: FormControl('', []),
      zip: FormControl('', []),
    }),
  ]),
  phone: FormControl('',[]),
});

I was getting the errors in the subforms, specifically in a FormGroup in the FormArray, but the top level form was not showing any errors. I had to look in the FormGroup in the FormArray.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.