W poprzedniej części spowodowaliśmy by generowały się atrybuty walidacyjne dla elementów dynamicznie generowanych. Jednakże mimo ich poprawnego dodawania do elementów, walidacja po stronie klienta nie działała dla dynamicznie dodanych elementów – przy tworzeniu byli to autorzy książki, zaś przy edycji nowi jeszcze nie dodani autorzy.
Rozwiązanie byłoby dość banalne, gdyby mi choć raz zadziałało, tak jak wspominał Procent u siebie na blogu, powinno wystarczyć wykonanie następującej linijki:
// parse wszystkich elementów zawartych w danym selector: $.validator.unobtrusive.parse(document); /* * parse pojedynczego elementu, drugi parametr określa czy dodać element * do walidatora - parse robi to na samym końcu, zaś parseElement wymaga * zdefiniowania, jeżeli wartość jestr true, to element nie zostanie dodany do * walidatora, zaś wartosć false spowoduje iż zostanie dodany */ $.validator.unobtrusive.parseElement(elemSelector, false);
Kod sparsuje nasz element (lub elementy w danym selector) i następnie doda go do pluginu walidacyjnego od jQuery. Niestety, dla mnie ten kod nigdy nie zadziałał. Nawet i teraz nie zadziała, a można to łatwo sprawdzić. W metodzie od JS odpowiedzialnej za dodanie elementu należy dodać następującą linijkę:
$.validator.unobtrusive.parse($element);
Lub nawet można się pokusić i dodać taką:
$.validator.unobtrusive.parse(document);
Na Create/Save walidacja po stronie klienta nie odpali się, zaś to co otrzymamy będzie odpowiedzą z serwera – można to poznać po ostatnim punkcie podsumowania błędów (Please fix all validation errors before clicking create/save once again).
Dlaczego tak się dzieje?
Plugin unobtrusive validation, po załadowaniu się strony forsuje jej sparsowanie – i dobrze. Jednak plugin validate działa rozsądnie. Raz sparsowany dokument zapisuje i jeżeli wykona się polecenie:
$('form[id=my]').validate();
To zostanie nam zwrócony już istniejący obiekt walidatora z informacją o wszystkich polach, jak i typach walidacji, które powinny zostać uruchomione w trakcie submit formularza.
Nie ważne to czy do metody validate() przekażemy opcję czy też nie, dokładnie ten kod to obrazuje:
$.extend($.fn, { // http://docs.jquery.com/Plugins/Validation/validate validate: function( options ) { // if nothing is selected, return nothing; can't chain anyway if (!this.length) { options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" ); return; } // check if a validator for this form was already created var validator = $.data(this[0], 'validator'); if ( validator ) { return validator; } // cut }, // cut });
Wyraźnie widać, że jeżeli zapisana wartość pod kluczem validator dla naszego elementu (w tym przypadku formularza) to zamiast wykorzystać przekazane opcje, zostanie nam zwrócony obiekt już utworzony.
Wyjść z sytuacji jest kilka:
- Usunięcie zapisanego obiektu o kluczu validator co dodanie elementu;
- Łączenie opcji za pomocą sprytnego kodu JS;
- Nierobienie nic i przeciążenie zdarzenia submit, tak by wykonać raz (nie licząc pierwszego wymuszonego przez unobtrusive validation) parsowanie;
Opcja pierwsza jest banalnie prosta, najpierw zamieniamy kod by zamiast parsować tylko nasz element to by parsować cały dokument lub określony formularz, a tuż przed tą linijką dodajemy linijkę kasującą ustawienia:
$.removeData($('form')[0], 'validator'); $.validator.unobtrusive.parse(document);
Opcja druga jest trochę bardziej skomplikowana i można zobaczyć jej przykładowe rozwiązanie tutaj – uwaga, selector nie działa tam poprawnie dla zagnieżdżonych elementów ze względu na nawiasy klamrowe.
Trzecia opcja jest najtrudniejsza ale to ze względu na jak działa plugin validate w jQuery i o tym będzie następnym razem.
Oczywiście poprawiony kod można znaleźć na github.