11import type { Observable } from 'rxjs' ;
2- import { catchError , map , of } from 'rxjs' ;
2+ import { catchError , finalize , map , of , switchMap , tap , timer } from 'rxjs' ;
33import { inject , Injectable , signal } from '@angular/core' ;
44import type { AbstractControl , AsyncValidator , ValidationErrors } from '@angular/forms' ;
55import { PokemonService } from '~features/pokemon/services/pokemon.service' ;
@@ -8,30 +8,40 @@ import { PokemonService } from '~features/pokemon/services/pokemon.service';
88export class PokemonValidator implements AsyncValidator {
99 private readonly pokemonService = inject ( PokemonService ) ;
1010 private readonly pokemonName = signal ( '' ) ;
11+ private readonly debounceMs = 500 ;
1112
1213 readonly pokemonId = signal ( - 1 ) ;
1314 readonly isPokemonValidating = signal ( false ) ;
1415
15- validate ( control : AbstractControl ) : Observable < ValidationErrors | null > {
16+ validate ( control : AbstractControl < string | null > ) : Observable < ValidationErrors | null > {
1617 const pokemonName = ( control . value ?? '' ) . toLowerCase ( ) . trim ( ) ;
1718
1819 if ( ! pokemonName ) {
1920 this . isPokemonValidating . set ( false ) ;
21+ this . pokemonId . set ( - 1 ) ;
2022 return of ( null ) ;
2123 }
2224
23- this . pokemonName . set ( pokemonName . toLowerCase ( ) ) ;
25+ this . pokemonName . set ( pokemonName ) ;
2426 this . isPokemonValidating . set ( true ) ;
25- return this . pokemonService . getPokemon ( pokemonName . toLowerCase ( ) ) . pipe (
26- map ( ( pokemon ) => {
27+ return this . validatePokemonName ( pokemonName ) . pipe (
28+ finalize ( ( ) => {
2729 this . isPokemonValidating . set ( false ) ;
28- this . pokemonId . set ( pokemon . id ) ;
29- return null ;
30- } ) ,
31- catchError ( ( ) => {
32- this . isPokemonValidating . set ( false ) ;
33- return of ( { pokemonName : true } ) ;
3430 } ) ,
3531 ) ;
3632 }
33+
34+ private validatePokemonName ( pokemonName : string ) : Observable < ValidationErrors | null > {
35+ return timer ( this . debounceMs ) . pipe (
36+ switchMap ( ( ) =>
37+ this . pokemonService . getPokemon ( pokemonName ) . pipe (
38+ tap ( ( pokemon ) => {
39+ this . pokemonId . set ( pokemon . id ) ;
40+ } ) ,
41+ map ( ( ) => null ) ,
42+ catchError ( ( ) => of ( { pokemonName : true } ) ) ,
43+ ) ,
44+ ) ,
45+ ) ;
46+ }
3747}
0 commit comments