1

Я использую jquery.validate в MVC 2 с MicrosoftMvcJQueryValidation. У меня есть аннотации данных по моей модели, которые затем переводятся в валидаторы jquery. Я использую модификацию для MicrosoftMvcJQueryValidation, как описано в Soe Tun, чтобы разрешить мои сообщения об ошибках появляться в сводке проверки, а не рядом с элементами управления.jquery.validate потерян на замене ajax и показывает только последнюю ошибку

Когда страница загружается, все работает должным образом. Проблема в том, что я использую формы ajax с режимом замены, чтобы переписать форму. Когда я это делаю, я теряю всю свою проверку на стороне клиента.

Валидация по-прежнему происходит на стороне сервера, а поля с ошибками правильно даны классам css для изменения их стиля. Однако в моем сводке проверки отображается только последнее сообщение об ошибке.

Контроллер не является чем-то особенным. Если модель действительна, выполните работу, иначе верните ту же модель обратно в представление.

Вот пример из моей АЯКС формы

<% using (Ajax.BeginForm("AddCreditCard", "Dashboard", 
     new { }, 
     new AjaxOptions() { 
      HttpMethod = "Post", 
      InsertionMode = InsertionMode.Replace, 
      UpdateTargetId = "quickpay-wrapper", 
      OnSuccess = "newPaymentSetup", 
      LoadingElementId = "loading-pane" 
      }, new { id="new-credit-card-form" })) { %> 

Вот измененное JavaScript.

jQuery.validator.addMethod("regex", function(value, element, params) { 
    if (this.optional(element)) { 
     return true; 
    } 

    var match = new RegExp(params).exec(value); 
    return (match && (match.index == 0) && (match[0].length == value.length)); 
}); 

// glue 

function __MVC_ApplyValidator_Range(object, min, max) { 
    object["range"] = [min, max]; 
} 

function __MVC_ApplyValidator_RegularExpression(object, pattern) { 
    object["regex"] = pattern; 
} 

function __MVC_ApplyValidator_Required(object) { 
    object["required"] = true; 
} 

function __MVC_ApplyValidator_StringLength(object, maxLength) { 
    object["maxlength"] = maxLength; 
} 

function __MVC_ApplyValidator_Unknown(object, validationType, validationParameters) { 
    object[validationType] = validationParameters; 
} 

function __MVC_CreateFieldToValidationMessageMapping(validationFields) { 
    var mapping = {}; 

    for (var i = 0; i < validationFields.length; i++) { 
     var thisField = validationFields[i]; 
     mapping[thisField.FieldName] = "#" + thisField.ValidationMessageId; 
    } 

    return mapping; 
} 

function __MVC_CreateErrorMessagesObject(validationFields) { 
    var messagesObj = {}; 

    for (var i = 0; i < validationFields.length; i++) { 
     var thisField = validationFields[i]; 
     var thisFieldMessages = {}; 
     messagesObj[thisField.FieldName] = thisFieldMessages; 
     var validationRules = thisField.ValidationRules; 

     for (var j = 0; j < validationRules.length; j++) { 
      var thisRule = validationRules[j]; 
      if (thisRule.ErrorMessage) { 
       var jQueryValidationType = thisRule.ValidationType; 
       switch (thisRule.ValidationType) { 
        case "regularExpression": 
         jQueryValidationType = "regex"; 
         break; 

        case "stringLength": 
         jQueryValidationType = "maxlength"; 
         break; 
       } 

       thisFieldMessages[jQueryValidationType] = thisRule.ErrorMessage; 
      } 
     } 
    } 

    return messagesObj; 
} 

function __MVC_CreateRulesForField(validationField) { 
    var validationRules = validationField.ValidationRules; 

    // hook each rule into jquery 
    var rulesObj = {}; 
    for (var i = 0; i < validationRules.length; i++) { 
     var thisRule = validationRules[i]; 
     switch (thisRule.ValidationType) { 
      case "range": 
       __MVC_ApplyValidator_Range(rulesObj, 
        thisRule.ValidationParameters["minimum"], thisRule.ValidationParameters["maximum"]); 
       break; 

      case "regularExpression": 
       __MVC_ApplyValidator_RegularExpression(rulesObj, 
        thisRule.ValidationParameters["pattern"]); 
       break; 

      case "required": 
       var fieldName = validationField.FieldName.replace(".", "_"); 
       if ($("#" + fieldName).get(0).type !== 'checkbox') { 
        // only apply required if the input control is NOT a checkbox. 
        __MVC_ApplyValidator_Required(rulesObj); 
       } 
       break; 

      case "stringLength": 
       __MVC_ApplyValidator_StringLength(rulesObj, 
        thisRule.ValidationParameters["maximumLength"]); 
       break; 

      default: 
       __MVC_ApplyValidator_Unknown(rulesObj, 
        thisRule.ValidationType, thisRule.ValidationParameters); 
       break; 
     } 
    } 

    return rulesObj; 
} 

function __MVC_CreateValidationOptions(validationFields) { 
    var rulesObj = {}; 
    for (var i = 0; i < validationFields.length; i++) { 
     var validationField = validationFields[i]; 
     var fieldName = validationField.FieldName; 
     rulesObj[fieldName] = __MVC_CreateRulesForField(validationField); 
    } 

    return rulesObj; 
} 

function __MVC_EnableClientValidation(validationContext) { 
    // this represents the form containing elements to be validated 
    var theForm = $("#" + validationContext.FormId); 

    var fields = validationContext.Fields; 
    var rulesObj = __MVC_CreateValidationOptions(fields); 
    var fieldToMessageMappings = __MVC_CreateFieldToValidationMessageMapping(fields); 
    var errorMessagesObj = __MVC_CreateErrorMessagesObject(fields); 

    var options = { 
     errorClass: "input-validation-error", 
     errorElement: "span", 
     errorPlacement: function(error, element) { 
      var messageSpan = fieldToMessageMappings[element.attr("name")]; 
      $(messageSpan).empty(); 
      $(messageSpan).removeClass("field-validation-valid"); 
      $(messageSpan).addClass("field-validation-error"); 
      error.removeClass("input-validation-error"); 
      error.attr("_for_validation_message", messageSpan); 
      error.appendTo(messageSpan); 
     }, 
     messages: errorMessagesObj, 
     rules: rulesObj, 
     success: function(label) { 
      var messageSpan = $(label.attr("_for_validation_message")); 
      $(messageSpan).empty(); 
      $(messageSpan).addClass("field-validation-valid"); 
      $(messageSpan).removeClass("field-validation-error"); 
     } 
    }; 

    var validationSummaryId = validationContext.ValidationSummaryId; 
    if (validationSummaryId) { 
     // insert an empty <ul> into the validation summary <div> tag (as necessary) 
     $("<ul />").appendTo($("#" + validationSummaryId + ":not(:has(ul:first))")); 

     options = { 
      errorContainer: "#" + validationSummaryId, 
      errorLabelContainer: "#" + validationSummaryId + " ul:first", 
      wrapper: "li", 

      showErrors: function(errorMap, errorList) { 
       var errContainer = $(this.settings.errorContainer); 
       var errLabelContainer = $("ul:first", errContainer); 

       // Add error CSS class to user-input controls with errors 
       for (var i = 0; this.errorList[i]; i++) { 
        var element = this.errorList[i].element; 
        var messageSpan = $(fieldToMessageMappings[element.name]); 
        var msgSpanHtml = messageSpan.html(); 
        if (!msgSpanHtml || msgSpanHtml.length == 0) { 
         // Don't override the existing Validation Message. 
         // Only if it is empty, set it to an asterisk. 
         //messageSpan.html("*"); 
        } 
        messageSpan.removeClass("field-validation-valid").addClass("field-validation-error"); 
        $("#" + element.id).addClass("input-validation-error"); 
       } 
       for (var i = 0; this.successList[i]; i++) { 
        // Remove error CSS class from user-input controls with zero validation errors 
        var element = this.successList[i]; 
        var messageSpan = fieldToMessageMappings[element.name]; 
        $(messageSpan).addClass("field-validation-valid").removeClass("field-validation-error"); 
        $("#" + element.id).removeClass("input-validation-error"); 
       } 

       if (this.numberOfInvalids() > 0) { 
        errContainer.removeClass("validation-summary-valid").addClass("validation-summary-errors"); 
       } 

       this.defaultShowErrors(); 

       // when server-side errors still exist in the Validation Summary, don't hide it 
       var totalErrorCount = errLabelContainer.children("li:not(:has(label))").length + this.numberOfInvalids(); 
       if (totalErrorCount > 0) { 
        $(this.settings.errorContainer).css("display", "block").addClass("validation-summary-errors").removeClass("validation-summary-valid"); 
        $(this.settings.errorLabelContainer).css("display", "block"); 
       } 
      }, 
      messages: errorMessagesObj, 
      rules: rulesObj 
     }; 
    } 

    // register callbacks with our AJAX system 
    var formElement = document.getElementById(validationContext.FormId); 
    var registeredValidatorCallbacks = formElement.validationCallbacks; 
    if (!registeredValidatorCallbacks) { 
     registeredValidatorCallbacks = []; 
     formElement.validationCallbacks = registeredValidatorCallbacks; 
    } 
    registeredValidatorCallbacks.push(function() { 
     theForm.validate(); 
     return theForm.valid(); 
    }); 

    theForm.validate(options); 
} 

// need to wait for the document to signal that it is ready 
$(document).ready(function() { 
    var allFormOptions = window.mvcClientValidationMetadata; 
    if (allFormOptions) { 
     while (allFormOptions.length > 0) { 
      var thisFormOptions = allFormOptions.pop(); 
      __MVC_EnableClientValidation(thisFormOptions); 
     } 
    } 
}); 

Я пытался двигаться звонки в нижней части в документе готовы в мой OnSuccess метод, но не сделал этого.

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

EDIT:

Вот немного больше информации о том, что я делаю

Вот обертка

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<QuickPayModel>" %> 

<div id="quickpay-wrapper"> 
<% if (Model.NewPaymentMethod) { %> 
    <% Html.RenderAction<DashboardController>(x => x.QuickPayNewMethod()); %> 
<% } else { %> 
    <% Html.RenderPartial("QuickPayMakePayment", Model); %> 
<% } %> 
</div> 

Вот сделать панель оплаты.

<%= Html.ClientValidationSummary(new { id = "valSumContainer" })%> 
<% Html.EnableClientValidation(); %> 

<% using (Ajax.BeginForm("QuickPay", "Dashboard", 
     new { }, 
     new AjaxOptions() { 
      HttpMethod = "Post", 
      InsertionMode = InsertionMode.Replace, 
      UpdateTargetId = "quickpay-wrapper", 
      OnSuccess = "updatePaymentHistory", 
      LoadingElementId = "loading-pane" 
      }, new { })) 
    { %> 
    <div class="horizontalline"><%= Html.Spacer() %></div> 
    <% ViewContext.FormContext.ValidationSummaryId = "valSumContainer"; %> 

    <p> 
    <%: Html.LabelFor(x => x.PaymentMethods)%> 

    <% if (Model.HasOnePaymentMethod) { %> 
      <%: Html.DisplayFor(x => x.SelectedPaymentMethodName) %> 
      <%: Html.HiddenFor(x => x.SelectedPaymentMethodId) %> 

    <% } else { %> 
     <%: Html.DropDownListFor(x => x.SelectedPaymentMethodId, Model.PaymentMethodsSelectList, "Select a Payment Method", new { })%> 
      <%: Html.HiddenFor(x => x.SelectedPaymentMethodName)%> 
     <script type="text/javascript"> 
      $(function() { 
       $("#PaymentMethods").change(function() { 
        $("#SelectedPaymentMethodId").val($(this).val()); 

        $("#SelectedPaymentMethodName").val($('option:selected', this).text()); 
       }); 
      }); 
     </script> 

    <% } %> 
    <%: Html.Spacer(12, 1) %><%: Ajax.ActionLink("New Payment Method", "QuickPayNewMethod", 
           new AjaxOptions() { InsertionMode = InsertionMode.Replace, 
                UpdateTargetId = "quickpay-wrapper", 
                OnSuccess = "newPaymentSetup", 
                LoadingElementId = "loading-pane" 
           })%> 
    <%: Html.ValidationMessageFor(x => x.SelectedPaymentMethodId)%> 

    </p> 

    <p> 
    <%: Html.LabelFor(x => x.Amount)%> 
    <%: Html.TextBoxFor(x => x.Amount, new { disabled = Model.UseInvoicing ? "disabled" : String.Empty, 
    title = Model.UseInvoicing ? "the total payment amount of all selected invoices" : String.Empty, 
    @class = "small" })%> 
    <%: Html.ValidationMessageFor(x => x.Amount)%> 
    </p> 

    <p> 
    <%: Html.LabelFor(x => x.PayDate)%> 
    <%: Html.TextBox("PayDate", Model.PayDate.ToShortDateString(), new { @class = "medium" })%> 
    <%: Html.ValidationMessageFor(x => x.PayDate)%> 
    </p> 

    <script type="text/javascript"> 
     $(function() { 
      quickPaySetup(); 
     }); 
    </script> 

    <div class="horizontalline"><%= Html.Spacer() %></div> 
    <%= FTNI.Controls.Submit("Submit Payment") %> 
    <%: Html.AntiForgeryToken() %> 

    <%: Html.ValidationMessage("Payment-Result")%> 
<% } %> 

А теперь мой новый способ оплаты панель

<script type="text/javascript"> 
    $(function() { 
     newPaymentSetup(); 
    }); 
    </script> 

    <h4>New Payment Method</h4> 

    <% if(Model.HasPaymentMethods) { %> 
     <span style="float:right;"> 
      <%: Ajax.ActionLink("Cancel", "QuickPay", 
           new AjaxOptions() { 
            HttpMethod = "Get", 
            InsertionMode = InsertionMode.Replace, 
            UpdateTargetId = "quickpay-wrapper", 
            OnSuccess = "quickPaySetup", 
            LoadingElementId = "loading-pane" 
           })%> 
     </span> 
    <% } %> 

    <div>Enter the information below to create a new payment method.</div><br /> 

    <%= Html.ClientValidationSummary(new { id = "valSumContainer" })%> 
    <% Html.EnableClientValidation(); %> 
<div id="new-payment-method-tabs"> 
    <ul> 
     <li><a href="#new-credit-card">Credit Card</a></li> 
     <li><a href="#new-ach">E-Check</a></li> 
    </ul> 
    <div id="new-credit-card"> 
     <% Html.RenderPartial("NewCreditCard", Model.CreditCardModel); %> 
    </div> 
    <div id="new-ach"> 
     <% Html.RenderPartial("NewACH", Model.ACHModel); %> 
    </div> 
</div> 

Каждая форма начинается с чем-то вроде этого

<% using (Ajax.BeginForm("AddCreditCard", "Dashboard", 
     new { }, 
     new AjaxOptions() { 
      HttpMethod = "Post", 
      InsertionMode = InsertionMode.Replace, 
      UpdateTargetId = "quickpay-wrapper", 
      OnSuccess = "newPaymentSetup", 
      LoadingElementId = "loading-pane" 
      }, new { id="new-credit-card-form" })) { %> 
    <% ViewContext.FormContext.ValidationSummaryId = "valSumContainer"; %> 

Начальные работы нагрузки. Любой аякс заменяет причину потери контекста формы, а не повторную инициализацию независимо от того, что я делаю. Форма возвращается, проверка выполняется на стороне сервера. Все недопустимые поля изменены (добавлены классы ошибок css), но в итоговой таблице отображается только последняя ошибка.

ответ

1

Я расскажу вам, как я это сделал всего несколько дней назад. Обратитесь к this question для получения более подробной информации.

В моем случае я показывал содержимое формы, используя вызов ajax внутри диалогового окна jquery. Когда звонок завершен, я просто заменяю содержимое диалогового окна контентом, отправленным обратно с контроллера.

Я изменил код внутри сценария Microsoft, как описано в моем вопросе, а затем вызвал метод init в готовом документе. Это также должно работать для вашего дела ...

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

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

+0

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

+0

Вы пытались установить контрольную точку внутри скрипта, чтобы узнать, вызван ли код после обновления ajax? Поместите точку останова внутри 'EnableClientSideVaidation()' с помощью Firebug. Если проверка на стороне клиента не происходит, это, вероятно, потому, что эта функция вызывает nt ... – Lorenzo

+0

Немного dubugging показывает, что после замены ajax, window.mvcClientValidationMetadata пуст. Моя проблема заключается в том, что форма ajax и вся проверка выполняются внутри div, который заменяется (и они должны). Таким образом, каждый раз, когда происходит обратный вызов ajax, все мои проверки клиентов теряются, и только одна ошибка всегда отображается в сводке проверки. – Josh

1

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

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

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

+0

' Я все еще хотел бы увидеть решение, в котором формы, содержащие сводки валидации и клиентскую проверку jquery с помощью аннотаций данных, могут быть записаны на страницу через обратные вызовы и все еще подключены и правильно функционирует. «Да. Это определенно то, что нам нужно. Кажется, что с MVC 3 в поле валидации все будет лучше и проще ... Мы посмотрим! – Lorenzo

Смежные вопросы