jquery.validate.unobtrusive nie działa z dynamicznymi wstawionymi elementami


99

Pracuję z ASP.Net MVC3, łatwiejszym sposobem korzystania z walidacji klienta byłoby włączenie jquery.validate.unobtrusive. Wszystko działa dobrze, jeśli chodzi o rzeczy prosto z serwera.

Ale kiedy próbowałem wprowadzić nowe „dane wejściowe” za pomocą javascript i wiedziałem, że muszę zadzwonić, $.validator.unobtrusive.parse()aby ponownie powiązać walidacje. Ale nadal wszystkie te dynamiczne pola wstrzykiwane nie działają.

Co gorsza, próbuję ręcznie bindować używając jquery.validatei to też nie działa. jakieś pomysły?


1
Jeśli przyszedłeś tu z Google, prawdopodobnie szukasz odpowiedzi @Sundara Prabu, ponieważ inne, które są masowo głosowane, są stare.
The Muffin Man

Odpowiedzi:


65

Stworzyłem rozszerzenie biblioteki jquery.validate.unobtrusive, które rozwiązało ten problem w mojej sytuacji - może być interesujące.

http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/


Myślę, że powinienem zagłosować na twoją odpowiedź jako właściwą. Swoją drogą, czy twoja biblioteka współpracuje z najnowszym MVC RC? czy po prostu to naprawili?
xandy,

1
Korzystając z powyższego kodu, upewnij się, że zaktualizowałeś go, aby zawierał kod w komentarzach, w przeciwnym razie może się zepsuć. W szczególności zmień dwie linie selektora, aby podwójnie cytować id.
Ryan O'Neill

1
W końcu udało mi się to uruchomić w moim scenariuszu po pewnym debugowaniu. Wydaje się, że nie powinien przejść do selektora wejścia, ale rodzica wejścia lub formularz, z powodu wywołania $.validator.unobtrusive.parse(). Ponadto wydaje się, że tylko dodaje nowe reguły, ale nie pobiera aktualizacji istniejących reguł?
lambinator

5
Ta odpowiedź powinna zawierać przynajmniej kości niedźwiedzia z wpisu na blogu. Odpowiedzi dotyczące samych linków są generalnie nie na temat SO
Liam

8
Chociaż ta odpowiedź ma ponad 3 lata, byłoby bardzo pomocne, gdybyś mógł opublikować jej podstawowe części tutaj, na tej stronie, w przeciwnym razie Twój post może zostać usunięty Zobacz często zadawane pytania, w którym wspomina się o odpowiedziach, które są „niewiele więcej niż link ”. Jeśli chcesz, możesz nadal dołączyć link, ale tylko jako „odniesienie”. Odpowiedź powinna istnieć sama, bez potrzeby korzystania z łącza.
Taryn

159

Wypróbowałem podejście Xhalenta, ale niestety nie zadziałało. Podejście Robin zadziałało i nie zadziałało. Działało świetnie w przypadku dynamicznie dodawanych elementów, ale jeśli spróbujesz użyć JQuery do usunięcia wszystkich atrybutów walidacji i rozpiętości z DOM, biblioteka walidacyjna nadal będzie próbowała je zweryfikować.

Jeśli jednak oprócz danych „validationData” usuniesz z formularza dane „unobtrusiveValidation”, zadziałało to jak urok do dynamicznego dodawania i usuwania elementów, które chcesz zweryfikować lub nie.

$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");

2
Xhalent na początku też nie działał dla mnie, potem zauważyłem, że parsowanie powinno być przekazane do kontenera dla nowych elementów, a NIE samych elementów - szybkim rozwiązaniem byłoby przekazanie całej formy zamiast elementu (elementów) - wtedy to działał jak urok.
Per Hornshøj-Schierbeck

1
jakiś pomysł, dlaczego mówi, że validatornie jest zdefiniowany? Mam odniesienia do walidacji i validation.unobtrusive. Walidacja działa do momentu wywołania tego kodu
Shawn Mclean,

4
Dzięki. Działa w przypadku zawartości dodanej do strony w widokach częściowych ASP.MVC dodanych za pośrednictwem wywołania AJAX.
Maksym Kozlenko

Dzięki, pomogło. Ale mam problem polegający na tym, że używam akordeonów na stronie, a jeśli akordeon jest zwinięty, nie uruchamia weryfikacji. Jak mogę to naprawić? Wiem, że gdybym poszedł na normalną wtyczkę jquery validate zamiast MVC3 dyskretny, musiałem powiedzieć$('#form').validate({ignore: ""})
parsh

1
U mnie zadziałało w PHP. po prostu dodając te informacje, ponieważ każdy komentarz wskazuje na .NET MVC. : P
finnTheHumin

42

Naprawdę podoba mi się prostota rozwiązań @viggity i @Robins, więc przekształciłem je w szybką, małą wtyczkę:

(function ($) {

    $.fn.updateValidation = function () {
        var $this = $(this);
        var form = $this.closest("form")
            .removeData("validator")
            .removeData("unobtrusiveValidation");

        $.validator.unobtrusive.parse(form);

        return $this;
    };
})(jQuery);

Przykładowe użycie:

$("#DischargeOutcomeNumberOfVisits")
    .attr("data-val-range-min", this.checked ? "1" : "2")
    .updateValidation();

zamień $ .validator.unobtrusive.parse ("#" + form.attr ("id")); z $ .validator.unobtrusive.parse (formularz);
Softlion

możesz też bezpiecznie usunąć .first (), ponieważ najbliższy zwraca tylko 1 element.
Softlion

Fajnie, podoba mi się to proste podejście
nixon

Działa pięknie zarówno w przypadku dodawania, jak i usuwania atrybutów data-val
Julian Dormon,

33

Mam ten sam problem. Odkryłem, że nie można dwukrotnie wywołać $ .validator.unobtrusive.parse () w tym samym formularzu. Podczas ładowania formularza początkowo z serwera formularz jest analizowany automatycznie przez dyskretną bibliotekę. Gdy dodasz element wejściowy dynamicznie do formularza i ponownie wywołasz $ .validator.unobtrusive.parse (), to nie zadziała. To samo dotyczy parseElement ().

Dyskretna biblioteka wywołuje metodę validate wtyczki jquery validate w celu ustawienia wszystkich reguł i komunikatów. Problem polega na tym, że po ponownym wywołaniu wtyczka nie aktualizuje nowego zestawu reguł, który podał.

Znalazłem jedno prymitywne rozwiązanie: przed wywołaniem metody analizy na dyskretnej bibliotece lib wyrzucam walidator formularzy:

$('yourForm').removeData("validator");

Teraz, gdy metoda validate jest wywoływana przez dyskretną bibliotekę, wszystkie reguły i komunikaty są odtwarzane, w tym dynamicznie dodawane dane wejściowe.

Mam nadzieję że to pomoże


Zasługuje na +1 - to prymitywne rozwiązanie, jak sam powiedziałeś, ale jest całkiem jasne, co to robi i w jakim stanie jesteś później
Per Hornshøj-Schierbeck

2
Z bloga Brada Wilsonsa: „Możesz również wywołać funkcję jQuery.validator.unobtrusive.parseElement (), aby przeanalizować pojedynczy element HTML”. Jakaś pomoc?
jamesfm

@Per Hornshøj-Schierbeck: @Robin van der Knaap: Spędziłem ostatnie 2-3 godziny, żeby to rozgryźć !! W każdym razie - to zadziałało WSPANIAŁE. Nieoczyszczony sprawia, że ​​czuję, że nie powinienem go używać - dlaczego miałbym nie chcieć tego robić?
KTF

2
Rozwiązanie jest nieco prymitywne, ponieważ wszystkie walidatory są usuwane i ponownie instalowane, w tym walidator dodawany dynamicznie. Byłoby lepiej, gdyby zaktualizowano tylko dynamicznie dodawany walidator. @Xhalent zapewnia czystsze rozwiązanie w swojej odpowiedzi, ale w zasadzie dyskretna biblioteka z MS powinna zostać zaktualizowana dla tego scenariusza.
Robin van der Knaap

9

Używam MVC 4 i JQuery 1.8, wygląda na to, że następujący fragment kodu jest potrzebny, aby umożliwić Jquery sprawdzanie poprawności zawartości dynamicznie wstrzykiwanej przez Ajax lub Jquery do DOM.

Zrobiłem funkcję modułową, która akceptuje obiekt Jquery nowo dodanego elementu. Jeśli sklonowałeś nową tabelę z identyfikatorem tblContactsza pomocą Jquery po kliknięciu przycisku, dołącz poniższą funkcję do pliku js

function fnValidateDynamicContent(element) {
    var currForm = element.closest("form");
    currForm.removeData("validator");
    currForm.removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse(currForm);
    currForm.validate(); // This line is important and added for client side validation to trigger, without this it didn't fire client side errors.
}

i nazwij to tak:

fnValidateDynamicContent("#tblContacts")

currform.validate (); właściwie powinno być currForm.validate (); (literówka). Dziękuję za udostępnienie, ale to zadziałało dla mnie
John Mc

1
@JohnMc naprawił teraz literówkę
Sundara Prabu

To jest jedyny, który działał dla mnie (mvc 4 i jquery 1.10)
The Muffin Man

4

Dlaczego nie użyć funkcji reguł bezpośrednio z dokumentu walidacji jQuery. Lubię to:

$('#newField0').rules('add', {
    required: true,
    minlength: 2
});
//use Html.ValidationMessage will renders a span element, unobtrusive need it to display errors
$('@Html.ValidationMessage("newField0")').insertAfter('#newField0');

2

Czerpiąc z rozwiązania Xhalenta oznaczonego jako odpowiedź powyżej, nieco go rozwinąłem.

$.validator.unobtrusive.parseDynamicContent = function (selector) {
    var $selector = $(selector),
        $jqValUnob = $.validator.unobtrusive,
        selectorsDataValAttr = $selector.attr('data-val'),
        $validationInputs = $selector.find(':input[data-val=true]');

    if ((selectorsDataValAttr !== 'true') && 
        ($validationInputs.length === 0)) { 
        return; 
    }

    if (selectorsDataValAttr === 'true') {
        $jqValUnob.parseElement(selector, true);
    }

    $validationInputs.each(function () {
        $jqValUnob.parseElement(this, true);
    });

    //get the relevant form
    var $form = $selector.first().closest('form');

    $jqValUnob.syncValdators($form);
};

/* synchronizes the unobtrusive validation with jquery validator */
$.validator.unobtrusive.syncValdators = function ($form) {
    if ($.hasData($form[0])) {
        var unobtrusiveValidation = $form.data('unobtrusiveValidation'),
            validator = $form.validate();

        // add validation rules from unobtrusive to jquery
        $.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
            if (validator.settings.rules[elname] == undefined) {
                var args = {};
                $.extend(args, elrules);
                args.messages = unobtrusiveValidation.options.messages[elname];
                $("[name='" + elname + "']").rules("add", args);
            } else {
                $.each(elrules, function (rulename, data) {
                    if (validator.settings.rules[elname][rulename] == undefined) {
                        var args = {};
                        args[rulename] = data;
                        args.messages = unobtrusiveValidation.options.messages[elname][rulename];
                        $("[name='" + elname + "']").rules("add", args);
                    }
                });
            }
        });
        // remove all validation rules from jquery that arn't in unobtrusive
        $.each(validator.settings.rules, function (elname, elrules) {
            if (unobtrusiveValidation.options.rules[elname] === undefined) {
                delete validator.settings.rules[elname];
            } else {
                $.each(elrules, function (rulename, data) {
                    if (rulename !== "messages" && unobtrusiveValidation.options.rules[elname][rulename] === undefined) {
                        delete validator.settings.rules[elname][rulename];
                    }
                });
            }
        });
    }        
};

$.validator.unobtrusive.unparseContent = function (selector) {
    var $selector = $(selector);

    // if its  a text node, then exit
    if ($selector && $selector.length > 0 && $selector[0].nodeType === 3) {
        return;
    }

    var $form = $selector.first().closest('form'), 
        unobtrusiveValidation = $form.data('unobtrusiveValidation');

    $selector.find(":input[data-val=true]").each(function () {
        removeValidation($(this), unobtrusiveValidation);
    });
    if ($selector.attr('data-val') === 'true') {
        removeValidation($selector, unobtrusiveValidation);
    }
    $.validator.unobtrusive.syncValdators($form);
};

function removeValidation($element, unobtrusiveValidation) {
    var elname = $element.attr('name');
    if (elname !== undefined) {
        $element.rules('remove');
        if (unobtrusiveValidation) {
            if (unobtrusiveValidation.options.rules[elname]) {
                delete unobtrusiveValidation.options.rules[elname];
            }
            if (unobtrusiveValidation.options.messages[elname]) {
                delete unobtrusiveValidation.options.messages[elname];
            }
        }
    }
}

Więc zasadniczo działa tak samo jak powyższe rozwiązanie Xhalent, ale dodałem możliwość usuwania reguł dla elementów, które usuwasz z domeny. Tak więc, gdy usuniesz elementy z Doma i chcesz, aby te reguły walidacji również zostały usunięte, wywołaj:

$.validator.unobtrusive.unparseContent('input.something');

1

Znalazłem skrypt kodu @ Xhalent w moim kodzie i zamierzałem go usunąć, ponieważ go nie używałem, co doprowadziło mnie do tego pytania SO.

Ten kod jest całkiem przejrzysty i prosty:

jQuery.fn.unobtrusiveValidationForceBind = function () {
    //If you try to parse a form that is already parsed it won't update
    var $form = this
       .removeData("validator") /* added by the raw jquery.validate plugin */
            .removeData("unobtrusiveValidation");  /* added by the jquery     unobtrusive plugin */

    $form.bindUnobtrusiveValidation();
}

Następnie, aby wywołać to rozszerzenie jQuery, po prostu użyj selektora, aby pobrać formularz:

$('#formStart').unobtrusiveValidationForceBind();

Altówka!


1

Spróbowałem odpowiedzi Viggity i na początku wszystko wydawało się działać. Ale po chwili zauważyłem, że walidacja staje się boleśnie wolniejsza, im bardziej dynamicznie dodawałem pozycje. Powodem było to, że jego rozwiązanie nie usuwa powiązań programów obsługi zdarzeń, ale za każdym razem dodaje nowe. Więc jeśli dodasz 5 pozycji, walidacja zostanie wykonana 6 razy, a nie tylko raz. Aby to naprawić, musisz dodatkowo usunąć powiązanie zdarzeń z wywołaniami removeData.

$("form").removeData("validator")
         .removeData("unobtrusiveValidation")
         .off("submit.validate click.validate focusin.validate focusout.validate keyup.validate invalid-form.validate");
$.validator.unobtrusive.parse("form");

1

W przypadku zawartości dynamicznej musisz zaktualizować Unobtrusive Validations jak poniżej i sprawdzić, czy Formjest ważny podczas przesyłania.

function UpdateUnobtrusiveValidations(idForm) {
    $(idForm).removeData("validator").removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse($(idForm));
};


$('#idDivPage').on('click', '#idSave', function (e) {
    e.preventDefault();
    if (!$('#idForm').valid()) {
        // Form is invalid … so return
        return false;
    }
    else {
        // post data to server using ajax call
        // update Unobtrusive Validations again
        UpdateUnobtrusiveValidations('#idForm');
    }
});

0

Bawiłem się tym przez jakiś czas, wyrzucając rozwiązania i próbując ponownie później (kiedy miałem trochę wolnego czasu, wierz lub nie).

Nie jestem pewien, czy to zachowanie zmieniłoby się w nowszych wersjach jquery (używamy 1.7.2), odkąd ten wątek został utworzony lub skomentowany jako ostatni, ale stwierdziłem, że .parseElement(inputElement)działa dobrze, gdy próbuję dodać dynamicznie utworzone elementy do formularza który ma już załadowany walidator. Zasugerował to już @jamesfm (15 lutego 2011) w jednym z powyższych komentarzy, ale przeoczyłem to kilka razy, gdy nad tym pracowałem. Dlatego dodaję to jako oddzielną odpowiedź, aby uczynić ją bardziej oczywistą i ponieważ uważam, że jest to dobre rozwiązanie i nie wymaga tak dużego obciążenia. Może to nie mieć zastosowania do wszystkich kwestii poruszonych w kolejnych odpowiedziach, ale myślę, że byłoby to rozwiązanie pierwotnego pytania. Oto jak sprawiłem, że mój działa:

//row & textarea created dynamically by an async ajax call further up in the code
var row = ...; //row reference from somewhere
var textarea = row.find("textarea");
textarea.val("[someValue]");

//add max length rule to the text area
textarea.rules('add', {
    maxlength: 2000
});
//parse the element to enable the validation on the dynamically added element
$.validator.unobtrusive.parseElement(textarea);

0

Po pierwsze, myślę, że wywołanie powinno być skierowane do .validator, a nie do walidacji, wtedy musisz podać identyfikator formularza

$.validator.unobtrusive.parse("#id");

Zakładam, że załadowałeś oba skrypty jquery.validate i jquery.validate.unobtrusive i wywołałeś metody Html.EnableClientValidation () i Html.EnableUnobtrusiveJavaScript ()? Czy możesz opublikować przykładowy kod dla swojej strony bazowej i dynamicznie ładowanego formularza?
Chris Allmark,

0

Jeśli chcesz dodawać i usuwać rzeczy z możliwością, że niektóre błędy są już wyświetlane, oto co przyszedłem. Opiera się głównie na różnych pomysłach na tej stronie z pytaniami. Używam wbudowanego destroy()zamiast po prostu usuwać atrybut danych dla walidacji JQuery.

function resetValidator($form: JQuery) {
    $form.validate().destroy();

    //reset unobtrusive validation summary, if it exists
    $form.find("[data-valmsg-summary=true]")
        .removeClass("validation-summary-errors")
        .addClass("validation-summary-valid")
        .find("ul").empty();

    //reset unobtrusive field level, if it exists
    $form.find("[data-valmsg-replace]")
        .removeClass("field-validation-error")
        .addClass("field-validation-valid")
        .empty();

    $form.removeData("unobtrusiveValidation");
}

Wywołujesz to przed dynamiczną modyfikacją danych wejściowych w formularzu. Następnie ponownie zainicjuj walidację po.

resetValidator($form);
//add or remove inputs here ...
$.validator.unobtrusive.parse($form);

Uwaga: Jeśli niektóre lub wszystkie dane wejściowe zostały sprawdzone i zawierają błędy, te błędy zostaną zresetowane ... ale powrócą poprawnie podczas następnej weryfikacji.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.