jquery.validate.unobtrusive не работает с динамически внедряемыми элементами

Я работаю с ASP.Net MVC3, более простым способом использования проверки клиента будет включение jquery.validate.unobtrusive. Все работает нормально, для вещей, которые прямо с сервера.

Но когда я пытаюсь ввести некоторые новые «входные данные» с помощью javascript, я знал, что мне нужно вызвать $.validator.unobtrusive.parse() для повторной привязки проверок. Но все же все эти динамически вводимые поля не работают.

Хуже того, я пытаюсь выполнить привязку вручную с помощью jquery.validate, и это тоже не работает. Есть предположения?


person xandy    schedule 10.12.2010    source источник
comment
Если вы пришли сюда из Google, вы, вероятно, ищете ответ @Sundara Prabu, поскольку другие, за которые массово проголосовали, устарели.   -  person The Muffin Man    schedule 25.11.2015


Ответы (13)


Я создал расширение для библиотеки jquery.validate.unobtrusive, которое решило эту проблему для моей ситуации - это может быть интересно.

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

person Xhalent    schedule 24.01.2011
comment
Я думаю, что я должен проголосовать за ваш ответ как за правильный. Кстати, ваша библиотека работает с последней версией MVC RC? или они просто исправили это? - person xandy; 24.01.2011
comment
Я использую его с MVC 3.0 RTM. - person Xhalent; 24.01.2011
comment
Я потратил целый день на эту проблему, сейчас 2:03, и я нашел это решение, работает! Благодарность!!! - person Shrage Smilowitz; 26.01.2011
comment
При использовании кода, указанного выше, убедитесь, что вы обновили его, чтобы включить код в комментарии, иначе он может сломаться. В частности, измените две строки селектора на двойные кавычки идентификатора. - person Ryan O'Neill; 14.07.2011
comment
@xhalent, как это работает с динамическим удалением поля из проверки? Я не удаляю из DOM, а фактически скрываю его и меняю URL-адрес действия формы. - person Shawn Mclean; 07.08.2011
comment
Также при использовании приведенного выше кода обязательно переместите форму за пределы динамического содержимого, форма должна быть статической. - person Anders; 10.10.2011
comment
Я думал, что это сработало сначала, но потом я заметил, что это работает только со строками, которые были добавлены при первом вызове, если следующий ответ ajax содержит больше строк, он проверяет только строки, которые были в первом ответе. Как я могу заставить его проверять все строки в ответе ajax? Спасибо! - person Anders; 10.10.2011
comment
Хорошо, заставил его работать с моим сценарием (таблица с входными элементами в каждой строке). Имейте форму внутри динамического содержимого, чтобы она загружалась при каждом вызове ajax, а затем вызывайте $.validator.unobtrusive.parse(- ваш-селектор-); - person Anders; 10.10.2011
comment
Наконец-то удалось заставить это работать для моего сценария после некоторой отладки. Похоже, что он не должен передаваться в селектор ввода, а должен передаваться родителю ввода или форме из-за вызова $.validator.unobtrusive.parse(). Кроме того, появляется только добавление новых правил, но не обновление существующих правил? - person lambinator; 27.10.2011
comment
У меня проблема: если я добавлю атрибуты data-val-* к элементам, а затем вызову parseDyanamicContent, он будет работать, как и ожидалось. Но когда я удаляю эти атрибуты data-val-* и снова вызываю parseDyanamicContent... проверка не удаляется. Было бы неплохо, если бы кто-нибудь придумал решение этой проблемы и Стив Лэмбс. - person Evan Larsen; 18.05.2012
comment
Отличное решение. Только одно замечание - лучше поменять $("[name='" + elname + "']").rules("add", args); на form.find("[name='" + elname + "']").rules("add", args); в своей библиотеке. Причина в том, что при наличии двух форм, содержащих элементы с одинаковыми именами, проверка для второй формы работает некорректно. Это был мой случай :) - person mayor; 13.11.2013
comment
Отличное решение. Исправлена ​​проблема, из-за которой я сначала удалял валидатор из формы и заставлял валидатор jQuery обращаться к его свойствам, прежде чем я мог воссоздать его после замены части формы динамическим содержимым. - person Christophe Geers; 26.11.2013
comment
Этот ответ должен содержать как минимум медвежьи кости сообщения в блоге. Ответы только на ссылки обычно не по теме для SO - person Liam; 19.03.2014
comment
Хотя этому ответу более 3 лет, было бы чрезвычайно полезно, если бы вы могли опубликовать основные части ответа здесь, на этом сайте, иначе ваше сообщение может быть удалено См. FAQ, где упоминаются ответы, которые являются "чуть больше, чем ссылка". Вы все еще можете включить ссылку, если хотите, но только как "ссылку". Ответ должен стоять сам по себе, без ссылки. - person Taryn; 28.03.2014

Я попробовал подход Xhalent, но, к сожалению, он мне не помог. Подход Робина работал и не работал. Он прекрасно работает для динамически добавляемых элементов, но если вы попытаетесь использовать JQuery для удаления всех атрибутов проверки и диапазонов из DOM, библиотека проверки все равно попытается проверить их.

Однако, если вы удалите данные «unobtrusiveValidation» формы в дополнение к «validationData», это сработает как шарм для динамического добавления и удаления элементов, которые вы хотите проверять или не проверять.

$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
person viggity    schedule 25.04.2011
comment
Xhalent сначала тоже не работал у меня, затем я заметил, что синтаксическому анализу должен быть передан контейнер для новых элементов, а НЕ сами элементы - быстрое решение состояло бы в том, чтобы передать всю форму вместо элемента (ов) - тогда это работал как шарм. - person Per Hornshøj-Schierbeck; 09.05.2011
comment
есть идеи, почему он говорит, что validator не определен? У меня есть ссылки как на валидацию, так и на validation.unobtrusive. Проверка работает, пока я не вызову этот код - person Shawn Mclean; 08.08.2011
comment
Спасибо. Он работает для содержимого, добавленного на страницу в частичных представлениях ASP.MVC, добавленных с помощью вызова AJAX. - person Maksym Kozlenko; 09.07.2012
comment
Спасибо, это помогло. Но я столкнулся с проблемой, когда я использую аккордеоны на странице, и если аккордеон свернут, он не запускает проверки. Как я могу это исправить? Я знаю, что если бы я выбрал обычный плагин проверки jquery вместо ненавязчивого MVC3, я должен был бы сказать $('#form').validate({ignore: ""}) - person parsh; 07.06.2013
comment
Вам нужно убедиться, что вы очищаете все события, добавленные в форму предыдущим валидатором, иначе у вас также будут работать обработчики событий из предыдущего валидатора. К сожалению, проверка jQuery не использует пространство имен для своих обработчиков :(. Вы можете исправить $.fn.validateDelegate, чтобы добавить пространство имен (т.е. '.validate'), а затем использовать `$('form').unbind('.validate') после удаление значений данных, но перед повторным анализом - person Robert Slaney; 31.10.2014
comment
Это сработало для меня в PHP. просто добавляя эту информацию, потому что каждый комментарий указывает на .NET MVC. :П - person finnTheHumin; 17.11.2014
comment
@RobertSlaney - звучит как важный момент, который обычно не рассматривается. Можете ли вы предоставить более подробный пример предлагаемого вами решения? - person xr280xr; 19.06.2015
comment
@Viggity, но этот метод очищает мои исходные сообщения проверки. Есть идеи, как это сохранить? - person Dhwani; 20.10.2015
comment
Вы также должны сказать $("form").off(".validate"), чтобы убедиться, что события удалены. В качестве альтернативы вы можете вызвать $("form").validate().destroy(), который делает это, а также удаляет данные. - person nfplee; 12.06.2020

На самом деле мне очень нравится простота решения @viggity и @Robins, поэтому я превратил его в небольшой плагин:

(function ($) {

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

        $.validator.unobtrusive.parse(form);

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

Пример использования:

$("#DischargeOutcomeNumberOfVisits")
    .attr("data-val-range-min", this.checked ? "1" : "2")
    .updateValidation();
person lambinator    schedule 27.10.2011
comment
заменить $.validator.unobtrusive.parse(# + form.attr(id)); с $.validator.unobtrusive.parse(form); - person Softlion; 28.12.2011
comment
вы также можете безопасно удалить .first(), поскольку ближайший возвращает только 1 элемент. - person Softlion; 28.12.2011
comment
Хорошо, мне нравится этот простой подход - person nixon; 16.11.2012
comment
Прекрасно работает как для добавления, так и для удаления атрибутов data-val. - person Julian Dormon; 12.07.2013

У меня такая же проблема. Я обнаружил, что невозможно дважды вызвать $.validator.unobtrusive.parse() в одной и той же форме. При первоначальной загрузке формы с сервера форма автоматически анализируется ненавязчивой библиотекой. Когда вы динамически добавляете элемент ввода в форму и снова вызываете $.validator.unobtrusive.parse(), это не сработает. То же самое касается parseElement().

Ненавязчивая библиотека вызывает метод проверки плагина проверки jquery для установки всех правил и сообщений. Проблема в том, что при повторном вызове плагин не обновляет заданный им новый набор правил.

Я нашел одно грубое решение: перед вызовом метода разбора в ненавязчивой библиотеке я выбрасываю валидатор формы:

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

Теперь, когда метод проверки вызывается ненавязчивой библиотекой, все правила и сообщения создаются заново, включая динамически добавляемые входные данные.

Надеюсь это поможет

person Robin van der Knaap    schedule 18.01.2011
comment
Заслуживает +1 - это грубое решение, как вы сами сказали, но довольно ясно, что оно делает и в каком состоянии вы остаетесь после этого. - person Per Hornshøj-Schierbeck; 03.02.2011
comment
Из блога Брэда Уилсона: вы также можете вызвать функцию jQuery.validator.unobtrusive.parseElement() для анализа одного элемента HTML. Любая помощь? - person jamesfm; 15.02.2011
comment
@Per Hornshøj-Schierbeck: @Robin van der Knaap: Я потратил последние 2-3 часа, чтобы понять это!! В любом случае - это сработало ЗАМЕЧАТЕЛЬНО. Неочищенный заставляет меня чувствовать, что я не должен его использовать — почему бы мне не хотеть этого? - person KTF; 06.05.2011
comment
Решение немного грубое, потому что все валидаторы удаляются и снова восстанавливаются, включая динамически добавленный валидатор. Лучше бы обновлялся только динамически добавляемый валидатор. @Xhalent предлагает более чистое решение в своем ответе, но в основном для этого сценария следует обновить ненавязчивую библиотеку от MS. - person Robin van der Knaap; 07.05.2011

Я использую MVC 4 и JQuery 1.8, похоже, что следующий фрагмент кода необходим для того, чтобы Jquery мог проверять динамически вводимый контент через Ajax или Jquery в DOM.

Я сделал модульную функцию, которая принимает объект Jquery вновь добавленного элемента. Если вы клонировали новую таблицу с идентификатором tblContacts с помощью Jquery нажатием кнопки, включите приведенную ниже функцию в свой файл 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.
}

и назовите это так:

fnValidateDynamicContent("#tblContacts")
person Sundara Prabu    schedule 28.02.2013
comment
currform.validate(); на самом деле должно быть currForm.validate(); (опечатка). Спасибо, что поделились, это сработало для меня - person John Mc; 17.03.2013
comment
@JohnMc исправил опечатку сейчас - person Sundara Prabu; 22.04.2013
comment
Это единственное, что сработало для меня (mvc 4 и jquery 1.10) - person The Muffin Man; 09.08.2013

Почему бы не использовать функцию правил непосредственно из документа проверки jquery. Нравится:

$('#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');
person zhangfx    schedule 07.03.2014

Взяв решение Xhalent, отмеченное как ответ выше, я немного расширил его.

$.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];
            }
        }
    }
}

Таким образом, в основном он по-прежнему работает так же, как решение Xhalent выше, но я добавил возможность удалять правила для элементов, которые вы удаляете из dom. Итак, когда вы удаляете элементы из Dom и хотите, чтобы эти правила проверки также были удалены, вызовите:

$.validator.unobtrusive.unparseContent('input.something');
person Evan Larsen    schedule 21.05.2012

Я попробовал ответ виггити, и сначала все, казалось, сработало. Но через некоторое время я заметил, что проверка становится болезненно медленной по мере того, как я добавляю более динамичные элементы. Причина заключалась в том, что его решение не отвязывает обработчики событий, а каждый раз добавляет новые. Таким образом, если вы добавите 5 элементов, проверка будет выполнена 6 раз, а не только один раз. Чтобы исправить это, вы должны отвязать события в дополнение к вызовам removeData.

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

Я нашел сценарий кода @ Xhalent в своем коде и собирался удалить его, потому что я его не использовал, что привело меня к этому вопросу SO.

Этот код довольно чистый и простой:

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();
}

Затем, чтобы вызвать это расширение jQuery, просто используйте селектор, чтобы захватить форму:

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

Виола!

person Brian Ogden    schedule 10.10.2015

В случае динамического содержимого вам необходимо обновить ненавязчивые проверки, как показано ниже, и проверить, действительно ли Form при отправке.

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');
    }
});
person Jagdeesh Motegowda    schedule 28.10.2015

Я некоторое время возился с этим, отбрасывая решения и пытаясь снова позже (когда у меня было свободное время, хотите верьте, хотите нет).

Я не уверен, что это поведение изменилось бы в более новых версиях jquery (мы используем 1.7.2), так как этот поток был создан или прокомментирован последним, но я обнаружил, что .parseElement(inputElement) отлично работает, когда я пытаюсь добавить динамически созданные элементы в форма, в которой уже загружен валидатор. Это уже было предложено @jamesfm (15 февраля 2011 г.) в одном из комментариев выше, но я упустил это из виду в первые несколько раз, когда работал над этим. Поэтому я добавляю его как отдельный ответ, чтобы сделать его более очевидным и потому, что я думаю, что это хорошее решение и не требует так много накладных расходов. Это может быть не актуально для всех вопросов, поднятых в последующих ответах, но я думаю, что это было бы решением исходного вопроса. Вот как я заработал:

//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);
person Ben    schedule 19.03.2013

Во-первых, я думаю, что вызов должен быть .validator, а не валидировать, тогда вам нужно передать идентификатор формы

$.validator.unobtrusive.parse("#id");
person Chris Allmark    schedule 21.12.2010
comment
Я предполагаю, что вы загрузили оба сценария jquery.validate и jquery.validate.unobtrusive и вызвали методы Html.EnableClientValidation() и Html.EnableUnobtrusiveJavaScript()? Можете ли вы опубликовать пример кода для своей базовой страницы и, возможно, динамически загружаемой формы? - person Chris Allmark; 21.12.2010

Если вам нужно добавить и удалить вещи с возможностью того, что некоторые ошибки уже отображаются, это то, с чем я пришел. Он основан в основном на различных идеях на этой странице вопросов. Я использую встроенный destroy() вместо того, чтобы просто удалить атрибут данных для проверки 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");
}

Вы вызываете его перед динамическим изменением входных данных в форме. Затем вы повторно инициализируете проверку после.

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

Примечание. Если некоторые или все входные данные были проверены и содержат ошибки, эти ошибки будут сброшены... но они будут правильно возвращены при следующей проверке.

person Yepeekai    schedule 11.06.2020