title: Angular reactive forms custom validator with an async RxJS call
body: <p><strong><em>See updates below</em></strong></p>
  
  <p>I realize my problem is that I'm very green at observables and RxJS.</p>
  
  <p>I have a custom validator like this:</p>
  
  <pre><code>export function ValidateFinalQty(service: MyService) {
      return (control: AbstractControl): { [key: string]: any } | null =&gt; {
          let qty = service.GetQty();
          if (control.value != qty) {
              return { FinalQuantityNotMatching: true };
          } else {
              return null;
          }
      };
  }
  </code></pre>
  
  <p>GetQty returns an RxJS Observable. 
  So how can I set this up so that my synchronous validator returns the right value depending on an asynchronous call? I need the return type of the validator to stay as <code>{ [key: string]: any } | null</code>.</p>
  
  <p>I saw a suggestion of something like <code>qty = await service.GetQty().first().toPromise();</code> but then I am returning a promise and I can't return a promise for the validator to work as I understand. </p>
  
  <p>How can I handle this?</p>
  
  <p>From my <code>package.json</code>:</p>
  
  <pre><code>"@angular/core": "7.1.0",
  "@angular/forms": "7.1.0",
  "rxjs": "6.3.3",
  "rxjs-compat": "^6.4.0",
  </code></pre>
  
  <hr>
  
  <p>UPDATE 5/23/19 Trying to Implement @Sachin's Answer.
  My breakpoints inside of map never get hit. I don't get any console logs and even if I remove the logic in the map and return null, it still always returns invalid. Very confused about what's happening here. My service is actually getting called, I've confirmed that. </p>
  
  <p>Any thoughts?</p>
  
  <pre><code>export class CustomAsyncValidator {
      static ValidateFinalQty(qtyService: FinalQtyService, brf: BatchRecordForm): AsyncValidatorFn {
          return (control: AbstractControl) =&gt; {
              return qtyService.postCalcFinalQuanity(brf)
                  .pipe(
                      map((qty) =&gt; {
                          console.log("running qty validator. value:", qty);
                          if (control.value !== qty) {
                              return { FinalQuantityNotMatching: true };
                          } else {
                              return null;
                          }
                      }),
                      catchError((err) =&gt; {
                          console.log("Error in final quantity validator", err);
                          return null;
                      }),
                      finalize(() =&gt; console.log("finished"))
                  );
          };
      }
  }
  </code></pre>
  
  <hr>
  
  <p><strong>UPDATE 6/7/2019</strong></p>
  
  <p>At the subscribe logging I am getting the right answer (null or { FinalQuantityNotMatching: true }) but my form control remains invalid. What am I doing wrong?</p>
  
  <p>Validator.ts</p>
  
  <pre><code>export class CustomAsyncValidator {
      static ValidateFinalQty(fqs: FinalQtyService, brf: BatchRecordForm) {
          return (control: AbstractControl) =&gt; {
              return fqs.postCalcFinalQuanity(brf).pipe(
                  debounceTime(500),
                  tap((action) =&gt; console.log("final qty", action)),
                  tap((action) =&gt; console.log("control.value", control.value)),
                  map(arr =&gt; (arr.Value !== `${control.value}`) ? { FinalQuantityNotMatching: true } : null)
              ).subscribe(x =&gt; console.log("subscribe output", x));
          };
      }
  }
  </code></pre>
  
  <p>component.ts</p>
  
  <pre><code> this.noteForm.addControl(this.finalQtyFormControlName, new FormControl(this.noteSubModuleForm.Value,
          [Validators.required, CustomAsyncValidator.ValidateFinalQty(this.finalQtyService, this.embrService.batchRecordForm)]));
  </code></pre>
  
  <hr>
  
  <p><strong>UPDATE 6/7/2019 #2</strong></p>
  
  <p>Following <a href="https://www.youtube.com/watch?v=zeX5CtFqkXQ" rel="nofollow noreferrer">https://www.youtube.com/watch?v=zeX5CtFqkXQ</a> I was able to make a directive based validator but would still prefer the have the validator in my ts if you're able to see what I did wrong in the previous update. </p>
  
  <p>@Directive({
      selector: "[validFinalQty]",
      providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: ValidateFinalQtyDirective, multi: true }]
  })</p>
  
  <pre><code>export class ValidateFinalQtyDirective implements AsyncValidator {
  
      constructor(private fqs: FinalQtyService, private embrService: EmbrService) { }
  
      validate(control: AbstractControl): Promise&lt;ValidationErrors | null&gt; | Observable&lt;ValidationErrors | null&gt; {
          return this.fqs.postCalcFinalQuanity(this.embrService.batchRecordForm).pipe(
              tap(x =&gt; {
                  console.log("final qty", x);
                  console.log("control.value", control.value);
              }),
              map(arr =&gt; (arr.Value !== `${control.value}`) ? { FinalQuantityNotMatching: true } : null)
          );
      }
  </code></pre>