ANGULAR 2 MODEL DRIVEN FORMS, cz. II – 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:

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.

 

3 Comments

  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?

    • mcsqueeb

      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!

Pozostaw odpowiedź takajednacosieuczyng2 Anuluj pisanie odpowiedzi

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *