Skip to content

Commit 83ab6bb

Browse files
authored
Merge pull request #180 from OrlPep/feat/pokemon-validation-debounce
feat(pokemon): debounce async validator and reset validating state in finalize
2 parents 8c5bb73 + 950d34c commit 83ab6bb

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed
Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Observable } from 'rxjs';
2-
import { catchError, map, of } from 'rxjs';
2+
import { catchError, finalize, map, of, switchMap, tap, timer } from 'rxjs';
33
import { inject, Injectable, signal } from '@angular/core';
44
import type { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms';
55
import { PokemonService } from '~features/pokemon/services/pokemon.service';
@@ -8,30 +8,40 @@ import { PokemonService } from '~features/pokemon/services/pokemon.service';
88
export 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

Comments
 (0)