16

In MVC Application, I want to render some parts of form dynamically (which are like PartialView on Controller Side)

In the partial view, i dont have Html.BeginForm() as the form tag is already rendered.

@model Introduction.Models.Human
<div>
    @Html.EditorFor(model => model.MarriageInformation.SpouseDetails)
    <div class="editor-label">
        @Html.LabelFor(model => model.MarriageInformation.DOM)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.MarriageInformation.DOM)
        @Html.ValidationMessageFor(model => model.MarriageInformation.DOM)
    </div>
</div>

Problem I am facing is in this case EditorFor does not return all the data-val-* attributes.

<div>
   <div class="editor-label">
    <label for="MarriageInformation_SpouseDetails_Name">Name</label>
</div>
<div class="editor-field"><input class="text-box single-line" id="MarriageInformation_SpouseDetails_Name" name="MarriageInformation.SpouseDetails.Name" type="text" value="" /> 

Is this by design or I m missing anything here? Is there any work around here?

The option i am thinking is after ajax load - strip the form and inject inner content.

Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
Ajay Bhosale
  • 1,872
  • 24
  • 35

2 Answers2

23

you're correct in assuming that this is by design. if you check the source you'll see the following:

// Only render attributes if unobtrusive client-side validation is enabled, and then only if we've
// never rendered validation for a field with this name in this form. Also, if there's no form context,
// then we can't render the attributes (we'd have no <form> to attach them to).
public IDictionary<string, object> GetUnobtrusiveValidationAttributes(string name, ModelMetadata metadata)

To fix this we can write an extension method for use in our partial view:

public static class HtmlExtentions
{
    public static void EnablePartialViewValidation(this HtmlHelper helper)
    {
        if (helper.ViewContext.FormContext == null)
        {
            helper.ViewContext.FormContext = new FormContext();
        }
    }
}

And then use it in our partial view:

@model Introduction.Models.Human
@{ Html.EnablePartialViewValidation(); }
<div>
    @Html.EditorFor(model => model.MarriageInformation.SpouseDetails)
    <div class="editor-label">
        @Html.LabelFor(model => model.MarriageInformation.DOM)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.MarriageInformation.DOM)
        @Html.ValidationMessageFor(model => model.MarriageInformation.DOM)
    </div>
</div>

The last step is to handle parsing the new validation attributes in our ajax callback:

$(function () {
    $('button').click(function (e) {
        e.preventDefault();
        $.get('@Url.Action("AddSpouse")', function (resp) { 
            var $form = $('form');
            $form.append(resp);                    
            $form.removeData("validator").removeData("unobtrusiveValidation");
            $.validator.u‌​nobtrusive.parse($form);
        })
    })
});
David Wick
  • 7,055
  • 2
  • 36
  • 38
  • To extend the answer, I found that just `$.validate.unobtrusive.parse($form);` is not sufficent. My final code look like `$form.removeData("validator").removeData("unobtrusiveValidation");$.validator.unobtrusive.parse($form);`. Check the related question - http://stackoverflow.com/q/4406291/655085 – Ajay Bhosale Jun 19 '11 at 10:48
  • +1 for `if (helper.ViewContext.FormContext == null){helper.ViewContext.FormContext = new FormContext();}`, it helped me out with something else – StuperUser Jul 26 '11 at 10:39
2

If you want the data validation tags to be there, you need to be in a FormContext. Hence, if you're dynamically generating parts of your form, you need to include the following line in your partial view:

@{ if(ViewContext.FormContext == null) {ViewContext.FormContext = new FormContext(); }}

You then need to make sure you dynamically rebind your unobtrusive validation each time you add/remove items:

$("#form").removeData("validator");
$("#form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("#form");
dazbradbury
  • 5,729
  • 5
  • 34
  • 38