title: Angular 6 reactive forms, synchronous cross field validation
body: <p><strong>@angular/forms: 6.1.7</strong></p>
  
  <p>I'm trying to create a custom validator that checks 2 <strong>formControl</strong>'s for inconsistent. </p>
  
  <p>When following the <a href="https://angular.io/guide/form-validation#cross-field-validation" rel="nofollow noreferrer">official angular documentation</a> I get a error when inputting value to one of the 2 forms: </p>
  
  <pre><code>Uncaught Error: Expected validator to return Promise or Observable.
      at toObservable (forms.js:596)
      at Array.map (&lt;anonymous&gt;)
      at FormControl.asyncValidator (forms.js:584)
      at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.AbstractControl._runAsyncValidator (forms.js:2454)
      at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.AbstractControl.updateValueAndValidity (forms.js:2427)
      at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.FormControl.setValue (forms.js:2764)
      at updateControl (forms.js:1699)
      at DefaultValueAccessor.onChange (forms.js:1684)
      at DefaultValueAccessor.push../node_modules/@angular/forms/fesm5/forms.js.DefaultValueAccessor._handleInput (forms.js:741)
      at Object.eval [as handleEvent] (ChangePasswordComponent.html:13)
  </code></pre>
  
  <p>It looks like angular is trying to fins a <strong>asyncValidator</strong> in this case, and not the <strong>sync</strong> version that i expect.</p>
  
  <p>Worth to mention is that i also have tried to return a <code>Observable&lt;ValidationErrors | null&gt;</code> that gives me the same error output.</p>
  
  <p><strong>Validator:</strong></p>
  
  <pre><code>import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
  
  export const passwordMatchValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null =&gt; {
    const password = control.get('password');
    const confirmPassword = control.get('confirmPassword');
  
    if (!password || !confirmPassword) {
      return null;
    }
  
    return password === confirmPassword ? null : { passwordMismatch: true };
  };
  </code></pre>
  
  <p><strong>Implementation:</strong></p>
  
  <pre><code>  this.formGroup = this.formBuilder.group(
        {
          password: ['', Validators.required, Validators.minLength(6)],
          confirmPassword: ['', Validators.required, Validators.minLength(6)]
        },
        {
          validators: passwordMatchValidator
        }
  </code></pre>
  
  <h2>Question</h2>
  
  <p>How do i create a custom synchronous cross field validator?</p>
  
  <h2>Question on the side</h2>
  
  <p>Is it possible to pass in the <em>formControl names</em> to the function instead of hard coding them?</p>
  
  <h2>UPDATE: Final solution</h2>
  
  <pre><code>import { FormGroup, ValidationErrors, ValidatorFn } from "@angular/forms";
  
  export const matchValidator = (firstControlName: string, secondControlName: string): ValidatorFn =&gt; {
    return (control: FormGroup): ValidationErrors | null =&gt; {
        const firstControlValue = control.get(firstControlName).value;
        const secondControlValue =  control.get(secondControlName).value;
        if (!firstControlValue || !secondControlValue) {
            return null;
        }
        return firstControlValue === secondControlValue ? null : { mismatch: true };
    }
  };
  </code></pre>
  
  <p><strong>Implementation:</strong> </p>
  
  <pre><code>this.formGroup = this.formBuilder.group(
        {
          password: ['', [Validators.required, Validators.minLength(6)]],
          confirmPassword: ['', [Validators.required, Validators.minLength(6)]],
          currentPassword: ['', Validators.required]
        },
        {
          validator: matchValidator('password', 'confirmPassword')
        }
  </code></pre>