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


99

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

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

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


1
Если вы пришли сюда из Google, вы, вероятно, ищете ответ @Sundara Prabu, поскольку другие, получившие массовое голосование, старые.
The Muffin Man

Ответы:


65

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

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


Думаю, я должен проголосовать за ваш ответ как за правильный. Кстати, ваша библиотека работает с последней версией MVC RC? или они это просто исправили?
xandy

1
При использовании кода, указанного выше, убедитесь, что вы обновили его, чтобы включить код в комментарии, иначе он может сломаться. В частности, измените две строки селектора на двойные кавычки идентификатора.
Райан О'Нил,

1
Наконец-то удалось заставить это работать для моего сценария после некоторой отладки. Похоже, что он должен передаваться не в селектор ввода, а в родительский элемент ввода или форму из-за вызова $.validator.unobtrusive.parse(). Кроме того, похоже, что он только добавляет новые правила, но не обновляет существующие?
lambinator

5
Этот ответ должен содержать, по крайней мере, «медвежьи кости» из сообщения в блоге. Ответы только по ссылкам обычно не по теме для SO
Лиам,

8
Хотя этому ответу более трех лет, было бы очень полезно, если бы вы могли опубликовать основные части ответа здесь, на этом сайте, иначе ваш пост рискует быть удаленным. См. FAQ, где упоминаются ответы, которые «едва ли больше, чем ссылка. '. Вы все еще можете включить ссылку, если хотите, но только в качестве «ссылки». Ответ должен стоять сам по себе, без ссылки.
Тарин

159

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

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

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

2
Xhalent сначала у меня тоже не работал, потом я заметил, что при синтаксическом разборе нужно передавать контейнер для новых элементов, а НЕ сами элементы - быстрое исправление - передать всю форму вместо элемента (ов) - тогда это работал как шарм.
Пер Хорнсхой-Ширбек,

1
любая идея, почему он говорит, validatorчто не определен? У меня есть как проверка, так и проверка. Ненавязчивые ссылки. Проверка работает, пока я не назову этот код
Шон Маклин

4
Спасибо. Он работает для контента, добавленного на страницу в частичных представлениях ASP.MVC, добавленных через вызов AJAX.
Максим Козленко

Спасибо, это помогло. Но я столкнулся с проблемой, когда я использую аккордеоны на странице, и если аккордеон свернут, он не запускает проверки. Как я могу это исправить? Я знаю, что если бы я выбрал обычный плагин проверки jquery вместо ненавязчивого MVC3, я должен был сказать$('#form').validate({ignore: ""})
парш

1
У меня это сработало на PHP. просто добавляю эту информацию, потому что каждый комментарий указывает на .NET MVC. : P
finnTheHumin

42

Мне действительно нравится простота решения @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();

заменить $ .validator.unobtrusive.parse ("#" + form.attr ("id")); с помощью $ .validator.unobtrusive.parse (форма);
Softlion

вы также можете безопасно удалить .first (), поскольку ближайший возвращает только 1 элемент.
Softlion


Прекрасно работает как для добавления, так и для удаления атрибутов data-val
Джулиан Дормон

33

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

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

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

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

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

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


Заслуживает +1 - это грубое решение, как вы сами сказали, но довольно ясно, что оно делает и в каком состоянии вы
останетесь

2
Из блога Брэда Уилсона: «Вы также можете вызвать функцию jQuery.validator.unobtrusive.parseElement (), чтобы проанализировать отдельный элемент HTML». Любая помощь?
jamesfm

@Per Hornshøj-Schierbeck: @Robin van der Knaap: Я потратил последние 2-3 часа, чтобы понять это !! Во всяком случае - это сработало ЧУДЕСНО. Crude заставляет меня чувствовать, что я не должен его использовать - почему бы мне этого не делать?
KTF

2
Решение немного грубое, потому что все валидаторы удаляются и снова восстанавливаются, включая динамически добавляемый валидатор. Было бы лучше, если бы обновлялся только динамически добавляемый валидатор. @Xhalent предоставляет более чистое решение в своем ответе, но в основном ненавязчивая библиотека от MS должна быть обновлена ​​для этого сценария.
Робин ван дер Кнаап,

9

Я использую 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")

currform.validate (); на самом деле должно быть currForm.validate (); (опечатка). Спасибо за то, что поделились, у меня это сработало
Джон Мак

1
@JohnMc исправил опечатку сейчас
Сундара Прабу

Это единственный, который у меня сработал (mvc 4 и jquery 1.10)
The Muffin Man

4

Почему бы не использовать функцию правил непосредственно из документа проверки 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');

2

Взяв решение 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');

1

Я нашел кодовый скрипт @ 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();

Альт!


1

Я попробовал ответить viggity, и сначала все, казалось, работало. Но через некоторое время я заметил, что проверка становится мучительно медленной, если добавить более динамично добавленные элементы. Причина в том, что его решение не отвязывает обработчики событий, а каждый раз добавляет новые. Поэтому, если вы добавляете 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");

1

В случае динамического содержимого вам необходимо обновить ненавязчивые проверки, как показано ниже, и проверить, 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');
    }
});

0

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

Я не уверен, изменилось бы это поведение в более новых версиях 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);

0

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

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

Я предполагаю, что вы загрузили оба сценария jquery.validate и jquery.validate.unobtrusive и вызвали методы Html.EnableClientValidation () и Html.EnableUnobtrusiveJavaScript ()? Можете ли вы опубликовать образец кода для своей базовой страницы и, возможно, динамически загружаемой формы?
Крис Аллмарк

0

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.