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 });
}
}