LoginSignup
1
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-03-23

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1