Dawid
Dawid

Reputation: 593

Angular custom validator for reactive form md-error not showing

I can't get my *ngIf to show up if passwords don't match.

<md-form-field>
    <input mdInput placeholder="Repeat password" type="password" formControlName="repeat">
    <md-error *ngIf="form.controls['repeat'].errors?.required">Field required</md-error>
    <md-error *ngIf="form.errors?.matchingPasswords">passwords don't match</md-error>
</md-form-field>

Here's my constructor

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      username:
      ['',
        Validators.compose([
          Validators.required,
          Validators.minLength(3),
          Validators.maxLength(30),
          this.validateUsername,
          this.validateUsernameAvailability
        ])
      ],
      email:
      ['',
        Validators.compose([
          Validators.required,
          Validators.maxLength(30),
          this.validateEmail
        ])
      ],
      password:
      ['',
        Validators.compose([
          Validators.required,
          Validators.minLength(8),
          Validators.maxLength(30),
          this.validatePassword
        ])
      ],
      repeat: ['',
        Validators.compose([
          Validators.required
        ])
      ]
    }, {validator: this.matchingPasswords('password', 'repeat')});
  }

  matchingPasswords(password, repeat) {
    return (group: FormGroup) => {
      // Check if both fields are the same
      if (group.controls[password].value === group.controls[repeat].value) {
        return null; // Return as a match
      } else {
        return { 'matchingPasswords': true }; // Return as error: do not match
      }
    };
  }

Here's a screenshot

@EDIT Using a simple <span> instead of <md-error> seems to fix it.

<span *ngIf="form.errors?.matchingPasswords">passwords don't match</span>

But why doesn't the <md-error> show up?

Upvotes: 1

Views: 942

Answers (1)

AVJT82
AVJT82

Reputation: 73377

Seems to be a 'bug' that needs a workaround.

md-error inside md-form-field just validates that specific input, taking no regard to any other inputs. So if you move that outside the md-form-field it will validate, but of course the css will be messed up in that case. The a fix is to use md-hint instead and just modify that with css to emulate the md-error:

<md-hint *ngIf="form.errors?.matchingPasswords">passwords don't match</md-hint>

Just to throw it out there you could skip the custom validator and use Custom Error Matcher like so:

myErrorStateMatcher(control: FormControl): boolean {
  if(control.parent.controls.password.value === control.value) {
    control.setErrors(null)
    return false;
  }
  else {
    control.setErrors({notSame:true})
    return true;
  }
}

in template:

<input mdInput formControlName="repeat" [errorStateMatcher]="myErrorStateMatcher">

DEMO

But with this you really have no control of when this is fired. Though with the code you have currently your custom validator is also fired whenever any change is happening to form. With that, check the sidenotes below.


Sidenotes:

If going with md-hint I'd wrap the password and repeat inside a nested form group and apply the custom validator to that nested form group, so that it's only fired when changes happen to either of those two form controls.

As for the repeat form control, I see no need to use any other validation, than to check if it matches the password field.

Upvotes: 1

Related Questions