Matching Passwords Validator

We first want to create a form with what’s called a “cross-field” validation.

What this means is that we want to validate data in our form, based on other data — in the same form.

For this, I will use Reactive Forms (yes, I love it), using the out-of-the-box utility FormBuilder. And then I’ll create the password validator.

initForm() will be called from the constructor

Look at the last line. See that we put the validator in the form level, and not in the control level?

This is how we do cross-fields validation. They apply to the form and not to a control.

Which means..

Our control is always valid!

mat-error Not Being Displayed

Let’s have a look at the html we’re using for the input

Now, I’m thinking that once the passwords do not match, we should be seeing the mat-error. Correct?

That is not the state if we’re using cross-field validation — and we are.

Why don’t I see the error?! (re-run)

Why is this happening?

Let’s look at a snippet from the official code of mat-form-field.

We can learn from this that only when the form-field (the control) says it has errors, it displays the mat-error using a transclusion.

So, it doesn’t matter if we even try to put the mat-error without any conditions, it won’t show until the control states that it has issues (validity or mentally 😅)

ErrorStateMatcher To The Rescue!

According to the official documentation and confirming by looking at the source code, errors in the control are shown if the control is invalid AND either touched or the form is submitted.

In order to make this work for us, we need to make the errors show if the form itself is invalid (since we’re talking about a form-level validation).

In that case, we need to define our own ErrorStateMatcher for the control.

An ErrorStateMatcher is a class that defines for the form-field when to display error messages.

It’s simple to create one. It will enforce us to create a isErrorState method which receives a FormControl and FormGroupDirective (reactive)/ NgForm (template-driven) arguments. Those are supplied by the form-field itself, so all we need to do is just work with them.

We’re saying now — If we started typing something in the input, and the form itself is invalid, state that the control has errors.

Let’s add this ErrorStateMatcher to the input:

Now, if we type mis-matching passwords we should see the error, and instantly!

Final result (re-run)

Demo

Here’s the demo for this.

Go ahead and play with it.