Javascript i sprawdzanie formularzy
Thursday, April 6th, 2006Niedawno znalezione: wygodna biblioteka ułatwiająca sprawdzanie poprawności danych wpisanych w formularzu, jeszcze przed wysłaniem ich do serwera. Samo sprawdzanie to nic nowego, ale tę bibliotekę spośród innych rozwiązań wyróżnia sposób, w jaki określa się poprawną zawartość: poprzez atrybut class pól formularzy i odpowiednio zdefiniowane, ogólne funkcje testujące.
Łatwiej to zademonstrować niż opowiedzieć:
<ul>
<li>Adres: <input name="email" type="text" class="simple_email"/></li>
<li>Hasło: <input name="password" type="password" class="sane_password"/></li>
<li>Używane shelle:
<select name="shell" multiple="1" class="mandatory">
<option value="bash">/bin/bash</option>
<option value="ash">/bin/ash</option>
<option value="csh">/bin/csh</option>
<option value="emacs">/usr/bin/emacs</option>
</select>
</ul>
<button type="submit" name="commit">Dodaj</button></td>
</form>
Ten fragment tworzy formularz z trzema polami: miejscem na email, hasło oraz listę używanych programów. Każde z nich ma przypisaną klasę, która określa jaką zawartość należy wymuszać:
- email: chciałbym, żeby można było wpisać adres email w najczęściej używanej, prostej postaci – użytkownik@domena.gdzieśtam (klasa simple_email),
- hasło: powinno to być sensowne hasło (klasa sane_password),
- używane shelle: należy wybrać przynajmniej jeden (klasa mandatory).
Jak widać, formularz pomimo dodania tej informacji nadal jest prosty i czytelny. Pozostaje jeszcze zdefiniować funkcje sprawdzające poprawność pól:
simple_email: function() {
return (/^\w+@\w+(\.\w+)+\.?$/.test(this.value));
},
return this.value.length > 3;
}
};
Klasa mandatory już jest zdefiniowana w bibliotece, więc nie trzeba jej dodawać. Funkcje te mogą być wspólne dla wielu formularzy, więc najlepiej umieścić je w osobnym pliku .js, wspólnym dla całego serwisu. Zostało już tylko włączenie sprawdzania formularzy poprzez wykonanie po załadowaniu strony:
Form.Validator.installForAllForms({'validators':Validators});
I już, efekt można obejrzeć tutaj. Jakie dokładnie są zalety takiego podejścia? Po kolei:
- formularze zawierają informacje o danych w postaci zwięzłej i czytelnej i dla maszyny, i dla człowieka,
- definicje funkcji testowych są zebrane w jednym, wspólnym dla całego serwisu miejscu, co oznacza że ewentualna zmiana sane_password dla wszystkich formularzy na coś bardziej skomplikowanego będzie szybka i wygodna,
- to, co trzeba napisać samemu, zostało ograniczone do naprawdę niezbędnego minimum: biblioteka faktycznie zawiera całą wspólną część kodu.
Uwaga, na wszelki wypadek: całe to sprawdzanie po stronie klienta oczywiście nie oznacza, że można zrezygnować z kontroli danych na serwerze. Nie należy mieć zaufania do przeglądarki. I nie o to tu chodzi, żeby całkowicie przenieść testy na klienta, tylko o szybsze poinformowanie użytkownika że coś wpisał źle.
Rozwiązanie ma jedną wadę: poprawność trzeba sprawdzać w dwóch miejscach, najprawdopodobniej w dwóch różnych językach programowania (ktoś tu pisze kod po stronie serwera w JS?), co oznacza powtarzanie informacji. Trzeba będzie się przyjrzeć, czy w takim Django dałoby się wyznaczać tablicę Validators na podstawie definicji modelu
Aktualizacja 2007/10/16: Miron zwrócił uwagę, że nie działał odsyłacz do strony testowej. Poprawiłem, dzięki.
Przy okazji wprowadziłem jedną zmianę, drobną ale ważną: od teraz pola z niepoprawną zawartością są wskazywane kolorem tła. Form.Validator ustawia takim elementom klasę "invalid", więc wymagało to tylko dopisania jednej linii CSS.

