W ostatnim postcie wspomniałem o trzeciej możliwości walidowania pól po stronie klienta:

Nierobienie nic i przeciążenie zdarzenia submit, tak by wykonać raz (nie licząc pierwszego wymuszonego przez unobtrusive validation) parsowanie

Może się zastanawiać ale po co mamy to przeciążać, tylko ze względu na te kilka dynamicznych pól? TAK :) (odpowiedź na to pytanie na końcu postu) oraz dlatego, że domyślna walidacja zwraca false, czyli blokuje jakiekolwiek akcje dalej. Jeżeli zostanie ona wykonana przed naszym kodem to nasz kod się nie uruchomi.

A co jakbyśmy chcieli wykonać jakieś inne niezbędne akcję w submit? Na przykład zadecydować czy walidacja ma zostać wykonana czy nie, albo jaki typ walidacji ma być wykonany?

U mnie w jednym z projektów mamy dwa przyciski do jednego formularza Save i Submit. Save ma na celu wykonanie podstawowej walidacji po stronie klienta i zapisanie zmian. Submit zaś rozszerza walidację po stronie klienta o dodatkowe pola (proporcje mniej więcej wyglądają tak, Save waliduje 5% formularza, gdzie Submit 100%). Gdybym miał polegać na standardowym działaniu plugina to raczej bym nie mógł tego osiągnąć – albo to co bym osiągnął nie było by powtarzalnym zachowaniem.

Więc co możemy zrobić?

Mamy dwie opcje:

  1. Zablokować zwracanie false i wykonać naszą operację tak jak chcemy;
  2. Zablokować submit w walidacji i zrobić to tak jak my chcemy.

Opcja pierwsza jest dość uciążliwa, za każdym razem przed i po kliknięciu na submit trzeba zablokować opcję:

$('form').validate().cancelSubmit = true;

Ale dzięki temu jeżeli sami nie określimy submitHandler (metoda uruchamiana kiedy walidacja jest poprawna) plugin zawsze zwróci true i nie zablokuje propagacji zdarzenia submit dalej. W naszym przypadku z zagnieżdżonymi listami, wystarczy, że wykasujemy kod odpowiedzialny za „resetowanie” walidatora i dodamy następujący kod czy to do metody bind czy też pod koniec strony Create/Edit:

    $('form').validate().cancelSubmit = true;

    $('form').submit(function (evt) {
        // blokada submit
        evt.preventDefault(); 

        $(this).validate().cancelSubmit = true;
        alert('no submit from jquery validation');
    });

Drugi sposób jest prosty i wymaga od nas wykasowania czyszczenia walidatora w metodach bind oraz dodanie następującego fragmentu na document on load:

$('form').validate().onsubmit = false;

Wiedząc, że dla jednego formularza może być tylko jedne ustawienia raz utworzone, tak naprawdę nie musimy się przejmować domyślnym parsowaniem dokumentu przez jquery.validate.unobtrusive – gdyż jeżeli wykona się on przed naszym kodem to zmienimy mu ustawienia, jeżeli zaś wykona się po naszym kodzie to opcje nie zostaną dodane a nasza wartość tak czy siak zostanie ustawiona.

Pozostaje nam już tylko ręczne wykonanie walidacji:

$(function () {
    library.book.edit.init();

    $('form').validate().onsubmit = false;

    $('form').submit(function (evt) {
        alert('no submit from jquery validation');
                
        $.removeData(this, 'validator');
        // tutaj mozemy uruchomic custom script parsowania
        $.validator.unobtrusive.parse(this);

        var isValid = $(this).valid();
        if (!isValid) {
            evt.preventDefault();
        } else {
            alert('form is valid');
        }
    });
});

I teraz sami możemy zadecydować co dalej.

Plusem tego podejścia w dynamicznych listach jest to, że tylko dwa razy parsujemy dokument – za pierwszym razem nie my a Microsoft to robi (możemy to rozwiązać edytując skrypt jquery.validate.unobtrusive), za drugim razem my. Ma to znaczący wpływa na wydajność aplikacji – przy dużej liczbie pól parsowanie może trochę trwać, uruchamianie go co nowy element przestaje się opłacać.