开发者

jQuery unobtrusive validation to validate part of a form

开发者 https://www.devze.com 2023-04-12 13:21 出处:网络
We have a ASP.NET MVC 3 application that uses unobtrusive jQuery validation. The page allows to add children objects to the model in the same go. The <form> contains a grid for the children, and

We have a ASP.NET MVC 3 application that uses unobtrusive jQuery validation. The page allows to add children objects to the model in the same go. The <form> contains a grid for the children, and some input fields for adding new children.

Simplified example with Issue as the Model and Subtasks as the children:

Issue.cshtml -> Defines the form and includes fields for the issue as well as its subtasks.

@model Issue
@using (Html.BeginForm("Create", "Issues", FormMethod.Post, new { id = "mainForm" })
{
    @Html.TextBoxFor(model => model.Summary)
    @Html.Partial("SubtaskFields", new Subtask())
    @Html.Partial("SubtasksGrid", model.Subtasks)
}

SubtaskFields.cshtml:

@model Subtask

@Html.TextBoxFor(model => model.Summary)

<button id="add">Add</button>

SubtasksGrid.cshtml:

@model IEnumerable<Subtask>

<table>
    @foreach (var subtask in Model)
    {
        <tr>
            <td>
                @subtask.Name
                <input type="hidden" name="Subtasks[@subtask.Index].Name" value="@subtask.Name"/>
            </td>
        </tr>
    }
</table>

The point is, when submitting the form, only the properties of the issue (Issue.Name, e.g.), plus the hidden fields for the children (Subtask.Name, e.g.) should be validated and submitted.

We have some javascript code that hooks on the "add" button, and adds a new subtask based on the values in the SubtaskFields.cshtml partial view. That script validates the input fields first. In order for this to work, we use the TextBoxFor etc. html helpers for the SubtaskFields.cshtml, too, rendering a dummy/default Subtask object (new Subtask()). Our javascript the uses $("#mainForm").validate().element(...) to validate the SubtaskFields before adding a new subtask.

The big problem with this approach is that the jQuery unobtrusive validation framework automatically hooks on the submit button and validates all fields within the form before submitting the form. I.e., even the subtask fields are validated. This does not make any sense. Say that the subtask name is mandatory (which means the user can only click on "add" if he has filled in a subtask name). But if the user does not click on "add", the values in the Subtask Fields don't have any meaning a开发者_如何学Cnd can in particular be left blank. In this case, in our current setting, jQuery validation fails because a mandatory field was left blank.

How can this be solved?


This is what we've come up with:

  1. Add an attribute to all subtask fields (which should not be validated when submitting the form), e.g. "data-val-ignore".
  2. Set the ignore setting on the form's validator to "[data-val-ignore]"
  3. For the add button, in order to validate the subtask fields (which are normally ignored), iterate over them, and for each field, remove the attribute, re-parse to genereate the rules, execute validation, add the attribute, parse one more time.

Ad 2:

$(document).ready(function () {
    $.data($('form')[0], 'validator').settings.ignore = "[data-val-ignore]";
});

Ad 3:

$(allSubtaskFields).each(function() {
    $(this).removeAttr("data-val-ignore");
    $.validator.unobtrusive.parseElement(this, false);
    if (!$("mainForm").validate().element($(this))) { result = false; }
    $(this).attr("data-val-ignore", "true");
    $.validator.unobtrusive.parseElement(this, false);
});


I would suggest moving @Html.Partial("SubtasksGrid", model.Subtasks) outside of your form, and either having it in a single separate form, or have the partial generate a form for each grid row.

This will address your validation problems with your main form, and should also permit you to simplify validation of each row in SubTasksGrid.


To validate part of the form, wrap the section or the controls you want to validate into a div with an #id or .class and do the following:

var validator = $("#myForm").validate();
var isValid = true;
$("myDivToBeValidated").find("*[data-val]").each(function (indx, elem) {
if (!validator.element(elem)) {
    isValid = false;
}
});

//this part of form is valid however there might be some other invalid parts 
if (isValid) 
   //do your action, like go to next step in a wizard or any other action
   goToNextStep();

I hope it is clear, if not please leave a comment. For more info about jQuery validation plugin and element() function, check this


Looks like you are working against the MVC egine here. I would use Editor templates and Display templates, EditorFor template for the stuff you wanna validate and post, and Display template for the stuff you dont wanna post and validate.. If you have a TextBoxFor in the display template make sure its binding property has no Required attribute, and if its a value type make it nullable.

0

精彩评论

暂无评论...
验证码 换一张
取 消