Wróć do strony głównej

ANGULAR 2 MODEL DRIVEN FORMS, cz. II

MODEL DRIVEN FORMS – zmiana zasad walidacji w locie

Jeśli zapoznałeś się już z podstawami Model Driven Forms, to czas na tzw. mięsko! W tym artykule zaprezentuję, jak podczas runtime’u zmieniać zasady walidacji (conditional validation).

Rozpatrzymy przypadek formularza, w którym:

  • użytkownik podaje obowiązkowo adres email, oraz jeśli chce, to również numer telefonu
  • użytkownik może wybrać, czy chce otrzymywać powiadomienia na maila (domyślnie), czy na telefon
  • jeśli wybierze, że na telefon, to pole z numerem staje się obowiązkowe (required).
  • jeśli wybierze płatność kartą, wszystkie pola dotyczące karty stają się obowiązkowe

Zanim przejdziemy do dalszej części artykułu, polecam spojrzeć jak wygląda stan od którego zaczynamy:

LIVE EXAMPLE

KLASA ABSTRACT CONTROL

Jeśli zapoznałeś się już z kodem, spójrzmy raz jeszcze, jak wygląda struktura naszego formularzu w kodzie:

Naszym celem jest dynamiczne dodawanie i usuwanie Validators.required do pola „phone”, jeśli użytkownik zaznaczy lub odznaczy radio button „sms”.

Rozpoczniemy od napisania metody, którą przypniemy na (click) przy każdym radio buttonie:

Oraz w HTML:

Jak słusznie zauważyłeś (bądź nie), formControlName może być identyczny dla wielu inputów. Przejdźmy do implementacji metody setSubscription, która obsłuży nam dynamiczną walidację:

Rozkładając powyższy kod na czynniki, znajome już Ci FormGroup oraz FormControl dziedziczą po klasie AbstractControl, która udostępnia nam min. następujące metody:

  • setValidators(newValidator) – jako parametr przyjmuje walidator, który chcemy ustawić. Jeśli nasz FormControl posiada już walidatory dodane w formBuilder.group(), zostaną one nadpisane.W przypadku dodania paru walidatorów, jako parametr przekazujemy tablicę z walidatorami. np:

  • setAsyncValidators(newValidator) – j/w, z tym, że dla asnychronicznych walidatorów
  • clearValidators() – czyści listę synchronicznych walidatorów
  • clearAnsyncValidators() – czyści listę asynchronicznych walidatorów
  • updateValueAndValidity({onlySelf? : boolean, emitEvent? : boolean}) – wykonuje re-kalkulację wartości i stanu walidacji FormControla / FormGroupa. Domyślnie update wartości i walidacji dotyczy również ancestorów (czyli FormGroupa, który jest nad FormControlem, lub wszystkich FormGroup’ów w górę, jeśli mamy zagnieżdżone FormGroup). Metoda przyjmuje opcjonalny parametr, przekazać możemy obiekt z dwoma opcjonalnymi właściwościami, w przypadku przekazania onlySelf jako true, refresh walidacji i wartości, będzie dotyczyć tylko danej kontrolki.

Brzmi klarownie. Jednak nie musimy się ograniczać do pojedynczego FormControl.

WALIDACJA W LOCIE GRUPY KONTROLEK

Możemy również dodawać walidację w locie na całe grupy kontrolek. Wyobraźmy sobie przykład, że użytkownik może wybrać płatność kartą, gdzie musi podać kod CVV, datę ważności karty, oraz numer karty. W takim przypadku nie ma sensu ustawiać walidatora na każdy FormControl osobno, tylko musimy zebrać to w grupę, co możemy zrobić w następujący sposób:

W templatce korzystamy z dyrektywy formGroupName, która wymaga obecności dyrektywy FormGroup. Wrzucamy do środka kontrolki, które mają zostać podpięte pod grupę. Następnie w formBuilderze:

Szybko i prosto – wołamy jeszcze raz formBuilder.group(). Na tym etapie, wartość modelu formularza wygląda następująco:

Model Driven Forms -wartości formularza w obieckie

Zagnieżdżony FormGroup, został wrzucony jako obiekt do głównego obiektu z wartościami całego formularza.

Na potrzeby artykułu, walidację całej grupy dodamy po prostu na kliknięcie guzika.

I nasza metoda setCardValidation():

Każdy formGroup posiada property controls, które zawiera wszystkie zagnieżdzone kontrolki (formControls).

W powyższym kodzie przeiterowaliśmy po każdym property obiektu card (czyli po każdej kontrolce grupy card), i ustawiliśmy walidację na required.

Dzięki takiemu trickowi, możesz dowolnej grupie przestawić wszystkie pola dynamicznie na required, zamiast np. wołać X razy setValidators na każdym polu, dublując kod.

Plunker podsumowujący artykuł:

LIVE EXAMPLE

PODSUMOWANIE

Wykorzystanie takich metod jak setValidators oraz clearValidators, jest bardzo przydatne w przypadku formularzy, gdzie użytkownik posiada wiele scenariuszy wypełniania formularza (np. użytkownik wybiera, że chce fakturę na firmę – automatycznie dodajemy walidację do pól związanych z firmą, NIP etc.). Więc warto pamiętać, że Angular nam to umożliwia.

 

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.

4 komentarzy

  1. takajednacosieuczyng2

    Hej 🙂

    1. Napotkałam w kodzie: const cardGroupControlsKeys = Object.keys(cardGroup.controls); na taki błąd Property 'controls' does not exist on type 'AbstractControl'.). Nie mogę znależć przyczyny problemu :/

    2. W Twoim plunkerze znalazłam isCardValidationEnabled: false;, gdzie tego używasz?

    • Hej:)
      isCardValidationEnabled – coś sprawdzałem podczas tworzenia arta i zapomniałem to usunąć, dzięki!:)

      Zdarza się, że kompilacja AOT w Angularze ma czasem problemy z .dot notation. Spróbuj:
      Object.keys(cardGroup["controls"])
      i powiedz czy dalej jest błąd?

      • takajednacosieuczyng2

        Tak jest lepiej 🙂

        setCardValidation(): void { const cardGroup = this.modelForm.controls['card']; const cardGroupControlsKeys = Object.keys(cardGroup['controls']); cardGroupControlsKeys.forEach((key) => { cardGroup['controls'][key].setValidators(Validators.required); cardGroup['controls'][key].updateValueAndValidity(); }); }

        Dzięki!

  2. Pingback: ANGULAR 2 MODEL DRIVEN FORMS, cz. III - Angular.love

Dodaj komentarz

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