.

.

piątek, 19 maja 2017

Walidacja formularza (client side)

Od pewnego czasu chodziło mi to po głowie i bardzo, bardzo chciałam to zrobić. Wiem, właściwa walidacja jest oczywiście po stronie servera - bezwarunkowo. Ale dobrze by było podpowiedzieć to i owo użytkownikowi BUKI, choćby po to, by nie próbował dodawać książek bez autora...

Tak więc myślałam o tym i nosiłam się z zamiarem. Ostatni tydzień był dość szalony (życie wzięło górę nad programowaniem ;)), ale potrzeba zmierzenia się z tematem walidacji formularza rosła i rosła. Wiedziałam (tak mi się przynajmniej wydawało), że będę potrzebować jakiegoś pluginu jQuery. Mało miałam czasu na kodowanie, ale w wolnych chwilach, pomiędzy tym a tamtym, w tramwaju i metrze przeglądałam różne blog posty i dokumentacje.

Tym sposobem trafiłam na jQuery-Form-Validator. Pierwsze wrażenie - dobrze udokumentowany plugin, wchodzę w to! Tzn. biorę. Potem mi zaświtało: "A może da się to jednak zrobić prościej, używając po prostu walidacji dostępnej w HTML5?". Nope, epic fail, bo walidacja walidacją, ale dane z formularza trzeba jeszcze przesłać do API, a z AJAXem nijak mi to nie grało. Wróciłam więc do pluginu.

Jak wspomniałam, dokumentacja obfita, moc możliwości. "Dużo tego, za dużo - myślę - jak na moje potrzeby. Napiszę to sama (ułańska fantazja początkującego! ;)), w końcu potrzebuję przecież naprawdę minimalnej walidacji: pole jest wymagane lub nie." Nope, epic fail #2. Nie jest to takie proste. Nie jest też tak straszliwie trudne (przy tych minimalnych potrzebach). Wykoncypowałam logikę walidacji, ale potrzebne jest jeszcze przecież manipulowanie CSSem - nadawanie i zdejmowanie klas z właściwych inputów, których dotyczy komunikat. Poczułam, że wynajduję koło na nowo / wyważam otwarte drzwi. Znów wróciłam więc do pluginu.

I co?

W telegraficznym skrócie:
użyłam "młotka" (walidacja HTML5), zrobiłam krzyżówkę (walidacja HTML5 + walidacja z wykorzystaniem pluginu), rozwiązałam krzyżówkę (modyfikując i zostawiając tylko walidację z użyciem pluginu).

W dłuższej opowieści:
Celem była walidacja dwóch pól formularza edycji książki - tytuł i autor, na zasadzie: pole jest wymagane. Na razie tylko tyle. Walidację inputów typu select zostawiam na później, bo tu będą relacje wzajemnej zależności (jeśli zostanie wybrany bookForm 'prose', to obligatoryjnie trzeba też wybrać też bookGenre; przy bookForm 'poetry' i 'drama' - nie można wybrać bookGenre, bo gatunki - ze względów praktycznych - mam zdefiniowane tylko dla prozy).

Co daje walidajca dostępna w HTML5?

  • fokus na niepoprawnie zwalidowanym polu (niekiedy - zależnie od przeglądarki - ze zmianą wyglądu pola) + wyświetlenie komunikatu (predefiniowanego co do treści i stylu)
  • wyświetlenie (predefiniowanego co do treści i stylu) komunikatu na evencie mouseenter

Poniżej zamieszczam screeny, jak to wygląda w Chromie:

HTML5 walidacja formularza

HTML5 walidacja formularza

Następnie dodałam komendą npm install --save jquery-form-validator, czyli wspomniany plugin. Zależności automatycznie dopisały się w pliku package.json, a ja ręcznie dodałam odpowiednie skrypty w index.html (czyli załączyłam pliki .js i .css). Po tej operacji w projekcie stała się dostępna - ku mojej wielkiej radości - funkcja $.validate:

jquery validate function

Kolejnym krokiem było skonfigurowanie walidacji. Ciekawiły mnie różne opcje, dostępne w pluginie, próbowałam więc początkowo połączyć walidację z HTML5 z tą 'pluginową', uruchamiając na formularzu mechanizm walidacji - funkcję $.validate z modułem HTML:

$.validate({
    form: '#add-and-edit-book',
    modules: 'html5',
});

Wyszedł z tego twór dość dziwaczny (być może gdzieś popełniłam błąd... to moja pierwsza walidacja formularza w życiu :)): przy próbie potwierdzenia formularza odpalał się jeden mechanizm, przy kolejnej - drugi, a przy trzeciej i każdej następnej - oba (a więc pojawiały się podwójne komunikaty o konieczności wypełnienia danego pola - bez sensu). Wciąż nijak nie współgrało to z AJAXem i zapisywaniem danych zmodyfikowanego itemu.

Szybko i bez żalu pożegnałam się więc z walidacją HTML5: z inputów formularza w HTML usunęłam atrybuty required, zostawiając tylko - wymagane przez plugin - data-validation="required". Zmodyfikowałam też funkcję $.validate - rejestrując w niej callback onSuccess:

1
2
3
4
5
6
$.validate({
    form: '#add-and-edit-book',
    onSuccess: function() {
        app.actions.updateBook();
    }
});

W ten sposób zmieniłam sposób wywołania akcji aktualizacji danych książki (http PUT) - wcześniej ten callback był rejestrowany na event handlerze (on click na buttonie 'Save'):

$('#container').on('click', '#save-changes-btn', app.actions.updateBook);

Podsumowując: po tych wszystkich zmianach button 'Save' zadziała (wyśle dane do API) wyłącznie wtedy, gdy walidacja formularza przebiegnie pomyślnie. Nie jest już możliwe usunięcie (świadome czy przypadkowe) tytułu lub autora danej książki podczas edytowania jej danych.


4 komentarze:

  1. jQuery validate ok, fajna biblioteka, tylko pytanie czy do samego sprawdzenia, czy pole nie jest puste na prawdę potrzeba bibliotek albo validacji html5?

    Czy nie wystarczy po prostu sprawdzenie:
    if (input.value.trim().length) {
    //kod gdy pole nie jest puste
    } else {
    /kod gdy pole puste
    }

    I teraz możesz łatwo obsługiwać CSS i odpowiednio "poinformować" użytkownika o błędach. Oczywiście "input" w moim kodzie to referencja do konkretnego pola formularza.
    Dodatkowo użyłem metody trim() aby uniknąć sytuacji, że jako wypełnione potraktujemy pole, w którym wpisane zostaną białe znaki (np. spacje).

    OdpowiedzUsuń
    Odpowiedzi
    1. Dzięki za sugestię. :) Fakt, trochę miałam poczucie, że szykuję się z armatą na muchę ;) w tym konkretnym przypadku (sprawdzanie, czy pole nie jest puste). Ale jak wspominałam, to dopiero pierwszy z elementów walidacji, której docelowo nie chciałabym robić ręcznie.

      Usuń
  2. Nie odbieraj tego jako krytykę, że zastosowałaś jQuery. Chciałem tylko zwrócić uwagę, że często wiele osób od razu zakłada konieczność podpinania biblioteki gdy de facto używają ledwo 1% jej możliwości. Ale to taka uwaga ogólna, nie tyle do Ciebie co do wszystkich czytelników :)
    Pozdrawiam,
    Tomek (PS. nie myślałaś o podpięciu komentarzy Disquss?)

    OdpowiedzUsuń
  3. Spoko, spoko, rzeczowe uwagi mile widziane. :) Disquss, powiadasz. Rozważę. Serdeczności! ;)

    OdpowiedzUsuń