Подтвердить что ты не робот

MVC 3 Razor @Html.ValidationMessageНе работает в частичной загрузке через jquery.load()

Я собрал здесь небольшой пример, чтобы воспроизвести проблему. У меня есть строго типизированное частичное представление _Name.cshtml:

@model ValidationInPartial.ViewModels.MyViewModel

<h2>@ViewBag.Message</h2>

    <fieldset>
        <legend>Name</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.MyName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MyName)
            @Html.ValidationMessageFor(model => model.MyName)
        </div>

        <a href="#" id="reload">Reload Name</a>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<script type="text/javascript">
    $(document).ready(function () {
        $("#reload").click(function () {
            $("#divName").load("Home/NameReload");
        });
    });
</script>

который изначально загружается и отображается внутри основного Index.cshtml

<div id="divForm">
    @using (Html.BeginForm()) {

        <div id="divName">
            @Html.Partial("_Name")
        </div>
    }
</div>

Поле MyName требуется, а проверка выполняется с помощью атрибута Обязательный в MyViewModel

namespace ValidationInPartial.ViewModels
{
    public class MyViewModel
    {
        [Required(ErrorMessage = "Please enter a Name.")]
        public string MyName { get; set; }
    }
}

После того, как страница будет загружена в первый раз, если вы нажмете кнопку "Создать", оставив поле пустым, появится сообщение "Пожалуйста, введите имя". показывает рядом с полем, и само поле становится розовым, что является ожидаемым поведением. Теперь, щелкнув ссылку "Обновить имя", которая делает вызов ajax (jquery.load(...)), частичная перезагрузка, вот код контроллера:

public PartialViewResult NameReload()
{
    MyViewModel myViewModel = new MyViewModel();
    ViewBag.Message = "Name Reloaded";
    return PartialView("_Name", myViewModel);
}

На этот раз, если вы нажмете кнопку "Создать", оставив поле пустым, сообщение подтверждения не появится рядом с полем, хотя поле становится розовым. Оказывается, при перезагрузке частичного @Html.ValidationMessageFor не отображает сообщение проверки как первый раз.

Вот файлы jquery, которые я использую

<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

Интересно, является ли это ошибкой в ​​том, как движок Razor отображает @Html.ValidationMessageFor или это проблема с jquery? Любая идея, почему это происходит?

Я также где-то читал, что вызов ajax теряет все скрипты для страницы, на самом деле мне нужно сохранить код javascript внутри частичного, чтобы они могли быть отображены и использованы снова.

В то же время я нашел обходное решение, которое нужно вручную отобразить в частичном, что должно было отображаться с помощью @Html.ValidationMessageFor, который:

<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="MyName"></span>

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

4b9b3361

Ответ 1

@NickBork имеет отличный ответ здесь. Ключевым моментом является то, что механизм рендеринга ASP.NET MVC не выводит валидацию script, если он не считает, что существует форма. В примере, представленном хакерами, он покупает вставку в форму, а затем был выбран внутренний фрагмент HTML из него, по существу выкидывая внешнюю оболочку формы.

Существует еще один способ, чтобы вы могли просто получить свое представление:

ViewContext.FormContext = new FormContext();

С помощью этого метода на самом деле не будет вывода кода FORM, но там будет разметка проверки.

Спасибо, Джон

Ответ 2

Разметка проверки (теги span, атрибуты пользовательского поля и т.д.) не отображаются, если ваши поля не содержатся в FORM. Сам модуль проверки не работает с элементами вне формы.

Когда ASP.NET отображает ваш частичный вид, элементы управления не входят в форму и, следовательно, не получают отображаемые элементы.

Когда вы загружаете частичный контент, вам нужно проанализировать HTML с помощью селектора jQuery.

В моем примере ниже у меня есть TBODY на родительской странице просмотра, содержащей строки. Когда мне нужно добавить дополнительные строки, я делаю вызов View, у которого были форма, таблица, tbody и коллекция строк.

$.ajax({
    type: "POST",
    url: "/controller/action",
    data: ({Your: 'dataHere'}),
    dataType: "html",
    success:
        function(response){
            $('tbody').append($('tbody',$(response)).html());

            //The validation plugin can't bind to the same form twice.
            //We need to remove existing validators
            $('form').removeData("validator");

            //Refresh the validators
            $.validator.unobtrusive.parse(document);
        },
    error:
        function(){
            alert('An error occured while attempting to add the new content');
        }
});

Обратите внимание, что я использую селектор jQuery для выбора строк, которые находятся внутри View/PartialView, которые загружаются с помощью AJAX:

$('tbody',$(response)).html()

Остальная часть оболочки просто добавляет строки из AJAX View/PartialView вызывающим родителям tbody:

$('tbody').append($('tbody',$(response)).html());

Пара других примечаний, после того, как плагин validator был запущен в форме, он не может быть вызван снова без повторного добавления его (см. jquery.validate.unobtrusive, не работающий с динамические вложенные элементы)

Чтобы исправить это, я сначала вызываю следующий метод для удаления всех валидаторов:

$('form').removeData("validator");
$("form").removeData("unobtrusiveValidation");

Затем я обновляю валидаторы, используя следующее:

$.validator.unobtrusive.parse(document);

Ответ 3

Я не могу вспомнить, где я нашел решение. Причина в том, что вы загружаете PartialView в представление, которое уже было проанализировано библиотекой jquery.validator.unobtrusive. Вам нужно повторно проанализировать ненавязчивую библиотеку

    function ReparseValidation(){
       jQuery.validator.unobtrusive.parse("#yourcontainer");
    }