diff --git a/src/app/core/validators/pokemon.validator.ts b/src/app/core/validators/pokemon.validator.ts index 911fa39d..c89e3518 100644 --- a/src/app/core/validators/pokemon.validator.ts +++ b/src/app/core/validators/pokemon.validator.ts @@ -1,5 +1,5 @@ import type { Observable } from 'rxjs'; -import { catchError, map, of } from 'rxjs'; +import { catchError, finalize, map, of, switchMap, tap, timer } from 'rxjs'; import { inject, Injectable, signal } from '@angular/core'; import type { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms'; import { PokemonService } from '~features/pokemon/services/pokemon.service'; @@ -8,30 +8,40 @@ import { PokemonService } from '~features/pokemon/services/pokemon.service'; export class PokemonValidator implements AsyncValidator { private readonly pokemonService = inject(PokemonService); private readonly pokemonName = signal(''); + private readonly debounceMs = 500; readonly pokemonId = signal(-1); readonly isPokemonValidating = signal(false); - validate(control: AbstractControl): Observable { + validate(control: AbstractControl): Observable { const pokemonName = (control.value ?? '').toLowerCase().trim(); if (!pokemonName) { this.isPokemonValidating.set(false); + this.pokemonId.set(-1); return of(null); } - this.pokemonName.set(pokemonName.toLowerCase()); + this.pokemonName.set(pokemonName); this.isPokemonValidating.set(true); - return this.pokemonService.getPokemon(pokemonName.toLowerCase()).pipe( - map((pokemon) => { + return this.validatePokemonName(pokemonName).pipe( + finalize(() => { this.isPokemonValidating.set(false); - this.pokemonId.set(pokemon.id); - return null; - }), - catchError(() => { - this.isPokemonValidating.set(false); - return of({ pokemonName: true }); }), ); } + + private validatePokemonName(pokemonName: string): Observable { + return timer(this.debounceMs).pipe( + switchMap(() => + this.pokemonService.getPokemon(pokemonName).pipe( + tap((pokemon) => { + this.pokemonId.set(pokemon.id); + }), + map(() => null), + catchError(() => of({ pokemonName: true })), + ), + ), + ); + } }