Wróć do strony głównej
Angular

Angular – Asynchroniczne walidatory

Dzisiaj wpis na temat asynchronicznej walidacji formularzy. O ile implementacja asynchronicznej walidacji w Angularze jest bardzo prosta, to już poprawne zakodowanie takiego walidatora wymaga pewnej wiedzy z RxJS.

Zanim przejdziemy do kodowania, zastanówmy się, kiedy może się przydać taki typ walidacji?

Na pewno w każdej sytuacji, kiedy chcemy mieć natychmiastowo feedback z serwera, czy dana wartość wpisana do formularza, istnieje już w bazie danych. Dzięki temu użytkownik może od razu poprawić wartość, zamiast czekać np. na informację po kliknięciu przycisku submit.

Rozważymy przykład, w którym użytkownik tworzy projekt i musi mu nadać unikalny klucz. W sytuacji, kiedy klucz jest już zajęty w bazie, chcemy od razu użytkownikowi wyświetlić informację o błędzie.

Asynchroniczny walidator – nieco teorii

Asynchroniczny walidator jest funkcją, która:

  • przyjmuje jako parametr instancję FormControl lub FormGroup
  • zwraca obiekt Observable
  • może przyjmować dodatkowe parametry (np. usługę), w takiej sytuacji tworzymy funkcję, która zwraca funkcję, parametr z kontrolką umieszczamy w funkcji zagnieżdżonej, a parametr z usługą w funkcji nadrzędnej
  • jeśli asynchroniczny walidator zwróci NULL, oznacza, że błąd nie wystąpił i wszystko jest OK, czyli identycznie jak w synchronicznych walidatorach

Oraz trzeba pamiętać, że:

  • Angular najpierw wykona synchroniczną walidację
  • w przypadku, jeśli synchroniczna walidacja zwróciła nam błędy, to asynchroniczne walidatory się NIE uruchomią

Implementacja walidatora

Poznaliśmy niezbędną teorię, więc czas zabrać się za mięsko 😉 Zbierzmy najpierw wymagania dla naszego walidatora. Czego oczekujemy?

  • w przypadku jak użytkownik zacznie wpisywać literki, chcemy opóźniać request do servera o 500ms, aby nie robić requesta co każdy znak (użyjemy timer z RxJS), co mogłoby być niezbyt dobre, zwłaszcza jak użytkownik bardzo szybko wpisuje znaki
  • w sytuacji, gdy poprzedni request się jeszcze nie skończył i został już wysłany nowy, to chcemy poprzedni anulować (użyjemy switchMap z RxJS)
  • walidator ma przyjmować usługę (serwis) jako parametr

Znamy już wymagania, przygotujmy jeszcze elementy, dzięki którym przetestujemy nasz walidator na StackBlitz.

Tworzę prosty serwis, udający zwrotkę z serwera, czy dany klucz jest już zajęty:

Naszym zajętym kluczem w bazie danych jest wartość „angularlove123”. Jeśli użytkownik spróbuje wpisać taki klucz do formularza, ma natychmiastowo otrzymać błąd. Opóźniamy Observable o 300ms, udając, że idzie odpowiedź z serwera. Oczywiście w tym miejscu, powinien iść prawdziwy strzał do API, który np. zwróci nam obiekt z wartością exists: true lub false.

Skoro mamy już serwis, czas zabrać się za walidator:

Po kolei:

  • używamy timer(500), aby opóźniać kontakt z serwerem i nie strzelać do API co każdą wpisaną literkę
  • następnie w switchMap sięgamy po metodę checkKey usługi ProjectService, dzięki switchMap poprzednie requesty są cancelowane, kiedy do strumienia wpadła już nowa wartość
  • do checkKey przekazujemy control.value, czyli wartość, którą wpisuje użytkownik do inputa
  • mapujemy odpowiedź, zwracamy obiekt z błędem jeśli klucz jest zajęty, a jeśli nie to zwracamy NULL

Podłączenie walidatora do kontrolki

Pozostaje nam teraz dodać walidator do kontrolki:

Templatka:


Powyżej, mamy dostęp do errora pod kluczem w jakim go dodaliśmy, czyli keyExists. Korzystamy z metody hasError aby sprawdzić, czy wystąpił.

Klasa komponentu:

Przekujemy do kontrolki nasz walidator  pod kluczem asyncValidators (tablica asynchronicznych walidatorów). Można również go dodać jako trzeci parametr w new FormControl, od razu w postaci tablicy:

Jednak zapis przy użyciu tablic jest mniej elegancki, w naszym przypadku wymusza na nas dodanie pustej tablicy synchronicznych walidatorów i jest mniej czytelny. Sugeruję dodawać walidatory pod kluczami validators i asyncValidators.

Link do przykładu na StackBlitz:

Example demo

Podsumowanie

Jak zauważyłeś, przy użyciu RxJS, możemy w bardzo łatwy sposób implementować wydajne, asynchroniczne walidatory. Framework Angular w przyjazny sposób umożliwia dodawanie ich do kontrolek lub całych grup kontrolek. Dodatkowo dzięki asynchronicznym walidatorom, nasza aplikacja staje się bardziej user friendly.

O autorze

Tomasz Nastały

JavaScript Developer, entuzjasta frameworka Angular oraz TypeScripta. Na co dzień lubię dzielić się wiedzą poprzez prowadzenie zajęć w jednym z trójmiejskich bootcampów i nagrywaniem kursów z Angulara.

Zapisz się do naszego newslettera. Bądź na bieżąco z najnowszymi trendami, poradami, meetupami i stań się częścią społeczności Angulara w Polsce. Rynek pracy docenia członków społeczności.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *