AngularJS
Angular6

Angularのカスタム非同期バリデータを定義するときはNG_ASYNC_VALIDATORSを使う。

Angularでカスタム非同期バリデータを作ったが、なぜかHttpClientでpostしてもgetしても動作せず。

公式ドキュメントにのがガイドに抜けがある。

https://v6.angular.io/guide/form-validation

例えば重複したメールアドレスがないかチェックするバリデータの定義は次のようになる。


unique-email.validator.ts


import { Directive, Injectable } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, Validator, ValidationErrors, AsyncValidator, NG_ASYNC_VALIDATORS } from '@angular/forms';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { UserService } from '../services/user.service';
/**
* 重複したメールアドレスを確認する。
*/

@Directive({
selector: '[uniqueEmail][ngModel]',
providers: [
{ provide: NG_ASYNC_VALIDATORS, useExisting: UniqueEmailValidator, multi: true }
]
})
export class UniqueEmailValidator implements AsyncValidator {

constructor(private userService: UserService) {
}

validate(c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
if (!c.value) {
return null;
}

return this.userService.getUserByEmail(c.value).pipe(
map(user => {
return user ? { uniqueEmail: true } : null;
}
)
);
}
}


一番大事なのは、@Directiveアノテーションのprovidersの設定。

NG_ASYNC_VALIDATORSを指定するのです。NG_VALIDATORSじゃだめなのです。


unique-email.validator.ts(抜粋)

@Directive({

selector: '[uniqueEmail][ngModel]',
providers: [
{ provide: NG_ASYNC_VALIDATORS, useExisting: UniqueEmailValidator, multi: true }
]
})

参考までに、ユーザーサービス。NG_ASYNC_VALIDATORSではなく、NG_VALIDATORSにするとthis.http.getが全く呼ばれません。


user.service.ts

import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';

import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { UserResult } from './user.result';

@Injectable()
export class UserService {
static EMAILEXISTS_URL: string = 'api/User/GetUserByEmail'
constructor(
private router: Router,
private http: HttpClient,
@Inject('BASE_URL') private baseUrl: string) {
}

public getUserByEmail(email: string){
if (!email) {
return null;
}
let params = new HttpParams().set("email", email);
return this.http.get<UserResult>(this.baseUrl + UserService.EMAILEXISTS_URL, { params: params });
}
}