Search code examples
asp.net-mvc-3jquery-validateunobtrusive-validation

jQuery unobtrusive validation to validate part of a form


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 and 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?


Solution

  • 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);
    });