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

MVC3 Ненавязчивая проверка не работает после вызова Ajax

Хорошо, вот сделка, я видел несколько сообщений по SO, относящихся к этой проблеме, но для меня ничего не работает.

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

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

Однако, если я попытаюсь загрузить тот же частичный через AJAX, как он здесь установлен, обязательная проверка не работает, каждый может опубликовать форму после этого и KABOOM.

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

У меня есть вид, который выглядит так...

  @model Area51.Models.Workflow.AddReportableItemToBatchActionModel
@{
    ViewBag.Title = "Add Reportable Item to Batch";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<script type="text/javascript">

    $(function () {
        var fadeDelay = 150;

        $(".jqDatePicker").datepicker({
            dateFormat: 'm/d/yy',
            onSelect: function (date) {
                $("#categoryContainer").show(fadeDelay);
            }
        });

        $('#Category').change(function () {
            RetrieveItemsForCategory();
            $("#itemContainer").show(100);
        });

        $('#Item').live('change', function () {
            RenderPartialForUOMByItem();           
        });



        function RetrieveItemsForCategory() {

            var category = $("#Category :selected").val();

            $.ajax({
                type: "POST",

                url: '@Url.Action("RenderPartialForLocationItemsByCategory","BatchWorkflow")',

                data: 'category=' + category,

                success: function (result) {
                    $("#itemContainer").html(result.toString());
                    $("#itemContainer").show(100);
                    RebindValidation();
                },

                error: function (req, status, error) {
                    alert("Sorry! Could not request items for your selection at this time.");
                }

            });


        }


        function RenderPartialForUOMByItem() {

            var item = $("#Item :selected").val();

            $.ajax({
                type: "POST",

                url: '@Url.Action("RenderPartialForUOMByItem","BatchWorkflow")',

                data: "item=" + item,

                success: function (result) {
                    $("#quantityContainer").html(result.toString());
                    $("#quantityContainer").show(100);
                    RebindValidation();
                },

                error: function (req, status, error) {
                    alert("Sorry! Could not request items for your selection at this time.");
                }

            });
        }

        function RebindValidation() {
            alert("Rebinding Validation");
            $.validator.unobtrusive.parse("#frmAddItem");
        }

    });      // End OnLoad Event
</script>

<h3 class="pageHeader">Batch : @Model.BatchName</h3>

<div align="center">

@{Html.BeginForm("AddItemToBatch", "BatchWorkflow", null, FormMethod.Post, new { id = "frmAddItem" });}

    @Html.ValidationSummary(true)

    <fieldset style="width:60%">
        <legend>Add an Item to the Batch</legend>     

     <div>       
          <h3>Select Date Item was Added</h3>
          @Html.EditorFor(x => x.EventDate,null)
          <br />
      </div>

      <div id="categoryContainer" style="display:none"> 
        <hr />
          <h3>Select an Inventory Category</h3>
          @Html.EditorFor(x => x.Category,null)
          <br />
      </div>

      <div id="itemContainer" style="display:none"> 
        @*   @{Html.RenderAction("RenderPartialForLocationItemsByCategory", "BatchWorkflow", new { category = Model.Category });}*@
      </div>


      <div id="quantityContainer" style="display:none"> 
        @*  @{Html.RenderAction("RenderPartialForUOMByItem", "BatchWorkflow", new { item = Model.Item });}*@
      </div>

      <div id="reportingDataContainer" style="display:none"> 
        <hr />
          <h3>What quantity of the batch was affected by this addition?</h3>
          @Html.EditorFor(x => x.ConsumedWineQuantity) (Gallons)
        <br />
        <hr />
          <h3>What was the increase in Batch Volume as a result of this addition?</h3>
          @Html.EditorFor(x => x.ProducedWineQuantity) (Gallons)
      </div>

        <div style="display:block">
        <div></div>        
            <span><button type="button" id="btnCancel" class="linkButton" value="Cancel" onclick="location.href='@Url.Action("Home","Home",null)';">Cancel</button></span>  
            <span><button type="submit" id="btnSubmit" class="linkButton" value="Add">Add Item</button></span>
        </div>


    </fieldset>
        @{ Html.EndForm(); }
</div>

Частичные представления очень просты, они в основном выглядят так...

@model Area51.Models.Workflow.AddReportableItemToBatchActionModel

      <hr />
          <h3>Select the Item to Add</h3>
          @Html.EditorFor(x => x.Item)
          <br />

Опять же, если я просто RenderPartial, проверка корректно работает, однако, когда я пытаюсь сделать это с помощью ajax, проверка продолжается. Предупреждение "Rebinding Validation" срабатывает, но $.validator.unobtrusive.parse( "# frmAddItem" ); похоже, ничего не делает.

Может ли кто-нибудь помочь с тем, что мне не хватает? Было бы очень благодарно.

< ======================== ОБНОВЛЕНИЕ 1 ==================== ========= >

Хорошо, я попробовал добавить $.validator.unobtrusive.parse( "# frmAddItem" ); в нижней части частичного представления в документе, готовом к событию, и он, похоже, тоже не работал, в основном ничего не изменилось, я все равно мог отправить форму.

Я нашел здесь сообщение: http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/, в котором упоминалось, что когда MVC-версия jqvalidation видит, что форма уже имеет правила проверки, связанные с ней, это просто игнорирует вызов .validator. Я внедрил расширение script, которое использовал этот джентльмен, и теперь валидация привязана к форме с использованием нового расширения. Я могу проверить это, добавив html в форму и вызвав новое расширение, и он переписывается в новое текстовое поле.

Однако это еще не полностью устранило проблему. Я использовал Firebug, чтобы проверить фактическое содержимое на полях, возвращающихся из вызова ajax, и заметил что-то очень странное.

Когда я использую RenderPartial для вызова действия, он выписывает следующий выбор:

<select id="Item" name="Item" data-val-required="The Item field is required." data-val-number="The field Item must be a number." data-val="true">

Однако, когда я делаю вызов ajax тому же правильному действию контроллера, он возвращает мне это:

<select id="Item" name="Item">

Я также попытался добавить теги script к частичному представлению, но это не устранило проблему. Есть ли причина, по которой вызов ajax будет лишать ненавязчивые теги проверки?

< ======================== ОБНОВЛЕНИЕ 2 ==================== ========= >

Хорошо, так что случилось, у меня был шаблон редактора для раскрывающегося списка, который взял список выбора и преобразовал его в html select. Я нашел сообщение, в котором упоминалось, что для того, чтобы получить атрибуты проверки данных для записи в шаблоне редактора, у вас должен быть контекст формы. Поскольку Html.RenderPartial выполнялся в форме, тогда шаблон редактора имел контекст формы для работы. Когда я просто пытался вызвать частичное через ajax, не было никакого контекста формы для работы, и вместо того, чтобы жаловаться, он просто не выписывал атрибуты проверки данных. Добавление нового контекста формы в шаблон редактора для SelectListDropDown устранило проблему.

@{ // fix to stop stupid crappy brad wilson mvc3 code from stripping the jq data valdiation attributes
    if (ViewContext.FormContext == null)
    {
        ViewContext.FormContext = new FormContext();
    }
}
4b9b3361

Ответ 1

$.validator.unobtrusive.parse("#frmAddItem"); будет работать. Обратите внимание, что это должно быть в частичном, который вы загружаете через ajax (ниже формы в частичном)

<form id="frmAddItem" method="POST" action="...">
    <!-- all the items -->
</form>
<script type="text/javascript">
    $.validator.unobtrusive.parse("#frmAddItem");
</script>

Ответ 2

Я добавляю свой опыт, поскольку приведенные выше рекомендации не работают для меня. Это решение помогло другим людям, которые попали на эту страницу с поисковой системы:

Добавьте OnSuccess="$.validator.unobtrusive.parse('YourFormName');" к вам AjaxOptions

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

@Ajax.ActionLink("This is a test to get unobtrusive javascript working",
                 "Name_of_your_controller_action",
                 new AjaxOptions { HttpMethod = "POST", 
                                   InsertionMode = InsertionMode.Replace, 
                                   UpdateTargetId = "UserDiv", 
                                   OnSuccess="$.validator.unobtrusive.parse('UserDetailsForm');"  
                                 }
                )

Это решение было найдено по адресу: http://blog.janjonas.net/2011-07-24/asp_net-mvc_3-ajax-form-jquery-validate-supporting-unobtrusive-client-side-validation-and-server-side-validation

Ответ 3

Я написал этот маленький фрагмент, который вы можете разместить в своем файле javascript, и он будет обрабатывать все ваши формы, загруженные ajax.

//enable unobtrusive validation for ajax loaded forms
$(document).ajaxSuccess(function (event, xhr, settings) {
    //process only if html was returned
    if ($.inArray('html', settings.dataTypes) >= 0) {
        //will parse the element with given id for unobtrusive validation
        function parseUnobtrusive(elementId) {
            if (elementId) {
                $.validator.unobtrusive.parse('#' + elementId);
            }
        }

        //get the form objects that were loaded.  Search within divs
        //in case the form is the root element in the string
        var forms = $('form', '<div>' + xhr.responseText + '</div>');

        //process each form retrieved by the ajax call
        $(forms).each(function () {
            //get the form id and trigger the parsing.
            //timout necessary for first time form loads to settle in
            var formId = this.id;
            setTimeout(function () { parseUnobtrusive(formId); }, 100);
        });
    }
});

Ответ 4

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

this.ViewContext.FormContext = new FormContext(); 

Ссылка

Ответ 5

Я мог бы получить только подтверждение для работы внутри OnComplete вместо OnSuccess:

Здесь код AJAX:

@using (Ajax.BeginForm("Index", null, 
                       new AjaxOptions { OnSuccess = "onSuccess", 
                                         OnComplete = "onComplete"}, 
                       new { id = "mainForm" }))

И вот мой script:

function onComplete(result) {
    $.validator.unobtrusive.parse("#mainForm");
    alert("Complete");
};