0

I have created a validator directive which calls a web.api method that checks if a name already exists.

I can't get the call to fire unless I subscribe to the event. But how do i return an observable when subscribing?

This is my service call:

doesNameAlreadyExist(name: string): Observable<boolean> {
    const url = `/exists?name=${name}`;
    return this.http.get<boolean>(url, httpOptions).pipe(
        debounceTime(2000),
        tap(_ => this.log(`checked application name=${name}`)))));
}

This is my directive:

import { Directive, OnInit } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS, ValidationErrors } from '@angular/forms';
//import { Observable } from 'rxjs/Observable';
import { Observable } from 'rxjs/Rx';
import { Subject }    from 'rxjs/Subject';
import { of }         from 'rxjs/observable/of';
import { debounceTime, distinctUntilChanged, switchMap, map } from 'rxjs/operators';

import { StringHelper } from '../classes/stringHelper'
import { ApplicationService } from '../services/application.service';
import { Application } from '../classes/application';

@Directive({
  selector: '[applicationNameAlreadyExists][ngModel]',
  providers: [
    { provide: NG_VALIDATORS, useExisting: ApplicationNameAlreadyExistsValidator, multi: true }
  ]
})

export class ApplicationNameAlreadyExistsValidator implements Validator, OnInit {
    private searchTerms = new Subject<string>();
    private nameAlreadyExists$: Observable<ValidationErrors>;

    constructor(private applicationService: ApplicationService) { } 

    validate(c: AbstractControl): Observable<ValidationErrors> {
        return this.applicationService
                   .doesNameAlreadyExist(c.value)
                   .map(result => (result ? { duplicateEmail: true } : null));
    };
}

I have tried every possible combination to get the method to fire without subscribing but it does not. If I subscribe then how to I return the observable?

ANy help would be greatly appreciated.

UPDATE The link provided does help but the error is not present in the errors object. My html is the following:

<input id="applicationName" name="applicationName" class="form-control" required maxlength="100" #applicationName="ngModel" applicationNameAlreadyExists 
[(ngModel)]="application.applicationName" />
{{applicationName.errors|json}}

After the method fires I dont have the key in the errors. I only have

{ "__zone_symbol__state": null, "__zone_symbol__value": [] }

How do I access this error?

AndyKing
  • 181
  • 1
  • 16
  • Possible duplicate of [How to implement Custom Async Validator in Angular2/4/5](https://stackoverflow.com/questions/35521583/how-to-implement-custom-async-validator-in-angular2-4-5) –  Jan 30 '18 at 10:42
  • (Sorry for the automatic message, but the answer on this question should answer you) –  Jan 30 '18 at 10:43
  • That has helped thanks. However using a promise results in the error message not being in the errors of the applicatioName control. I'll update my question above to illustrate. – AndyKing Jan 30 '18 at 11:01
  • 1
    It's not about using a promise. It's about realizing that what you have defined is not a validator, but an **async** validator. Which should thus be provided with the token NG_ASYNC_VALIDATORS, and not NG_VALIDATORS. And which must implement AsyncValidator, not Validator. – JB Nizet Jan 30 '18 at 11:11
  • Ok so i've implemented AsyncValidator but still can't get access to the message returned. Do you have an example how to do this? – AndyKing Jan 30 '18 at 11:14
  • I had to set the provide to NG_ASYNC_VALIDATORS so thanks JB Nizet. I know get the message through. FUnnily enough implementing Validator or AsyncValidator made no difference. – AndyKing Jan 30 '18 at 11:33
  • An interface doesn't exist at runtime. It's just there to let the compiler know that your intention is to have a method conforming to the signature defined in the interface. NG_ASYNC_VALIDATORS is absolutely needed. – JB Nizet Jan 30 '18 at 12:20

0 Answers0