11

I have a farily straight forward form that renders personal data as a partial view in the center of the form. I can not get client side validation to work on this form. I started chasing down the generate html and came up with the same model field rendered on a standard form and a partial view.

I noticed that the input elements are correctly populated on the first call, @html.partial, the following only happens when the partialview is reloaded via an ajax request.

First the header of my partial view, this is within a Ajax.BeginForm on the main page.

@model MvcMPAPool.ViewModels.EventRegistration
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"         type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function ()
{
    $(".phoneMask").mask("(999) 999-9999");
});
</script>

@{
    var nPhn = 0;
    var dTotal = 0.0D;
    var ajaxOpts = new AjaxOptions{ HttpMethod="Post", UpdateTargetId="idRegistrationSummary", OnSuccess="PostOnSuccess" };
    Html.EnableClientValidation( true );
    Html.EnableUnobtrusiveJavaScript( true );
}

Here is the razor markup from the partial view:

@Html.ValidationMessageFor(model=>Model.Player.Person.Addresses[0].PostalCode)
<table>
    <tr>
        <td style="width:200px;">City*</td>
        <td>State</td>
        <td>Zip/Postal Code</td>
    </tr>
    <tr>
        <td>@Html.TextBoxFor(p=>Model.Player.Person.Addresses[0].CityName, new { style="width:200px;", maxlength=50 })</td>
        <td>
        @Html.DropDownListFor(p=> Model.Player.Person.Addresses[0].StateCode
                                 , MPAUtils.GetStateList(Model.Player.Person.Addresses[0].StateCode))</td>
        <td>
        <div class="editor-field">
        @Html.TextBoxFor(p=>Model.Player.Person.Addresses[0].PostalCode, new { style="width:80px;", maxlength=10 })
        </div>
        </td>
    </tr>
</table>

Here is the rendered field from the partial view:

        <td>
        <div class="editor-field">
        <input id="Player_Person_Addresses_0__PostalCode" maxlength="10" name="Player.Person.Addresses[0].PostalCode" style="width:80px;" type="text" value="" />
        </div>
        </td>

Here is the same model field rendered in a standard view:

        <div class="editor-field">            
            <input data-val="true" data-val-length="The field Postal/Zip Code must be a string with a maximum length of 10." data-val-length-max="10" data-val-required="Postal or Zip code must be provided!" id="Person_Addresses_0__PostalCode" maxlength="10" name="Person.Addresses[0].PostalCode" title="Postal/Zip Code is required" type="text" value="" />       
            <span class="field-validation-valid" data-valmsg-for="Person.Addresses[0].PostalCode" data-valmsg-replace="true"></span>        
        </div>

Notice that the partial view rendering has no data-val-xxx attributes on the input element.

Is this correct? I do not see how the client side validation could work without these attributes, or am I missing something basic here?

Scott Norberg
  • 389
  • 1
  • 4
  • 11
  • See the [`@using (Html.BeginSubForm())` answer](http://stackoverflow.com/a/8750181) to [ASP.NET MVC 3: Generate unobtrusive validation when BeginForm is on the layout](http://stackoverflow.com/questions/4997269/asp-net-mvc-3-generate-unobtrusive-validation-when-beginform-is-on-the-layout). – Joel Purra Apr 11 '12 at 19:22

2 Answers2

18

In order to create the unobtrusive validation attributes, a FormContext must exist. Add the following at the top of your partial view:

if (this.ViewContext.FormContext == null) 
{
    this.ViewContext.FormContext = new FormContext(); 
}
counsellorben
  • 10,924
  • 3
  • 40
  • 38
  • I checked the FormContext and it is already set, so everything works as it originally did. – Scott Norberg Sep 20 '11 at 16:25
  • I moved the partial view into the main view, and the validation works correctly. I supposed the form could be rewritten and leave it that way, but I would really like to know how to make this work. – Scott Norberg Sep 20 '11 at 16:28
  • 2
    Your PartialView does not have `@using Html.BeginForm()` or `@using Ajax.BeginForm()` declared, so there is no `FormContext` in the PartialView. If it is called from a View, a FormContext is passed to it. If it is called from an action in your controller, no FormContext is passed. To have it work in that case, the PartialView must instantiate the FormContext. This is done by adding the code block in my answer at the top of the PartialView. – counsellorben Sep 20 '11 at 16:42
  • I found a similar [article](http://stackoverflow.com/questions/6401033/editorfor-not-rendering-data-validation-attributes-without-beginform) so I added a onclick handler on my submit button and added the $.validate.unobtrusive.parse call and now the form validates. I have seen this is several posts but it didn't click on just what the parse was doing. Anyway, that seems to have helped. – Scott Norberg Sep 20 '11 at 17:23
  • This turns out to be the problem. It was buried in amongst several other issues so I didn't "get it" right away. Thanks. – Scott Norberg Sep 21 '11 at 12:23
  • I suppose someone should add a comment to ask MS to provide a non-hacky way to output validation attributes... – Dave Nov 01 '11 at 19:18
  • This did the trick for me as long as I called "$.validator.unobtrusive.parse($("form"));" after the contents where added to the page. – anAgent Jun 26 '12 at 15:55
  • Does not help me. Here's what's generated all the time, can't figure out, where is it from: `` Maybe it's jquery ORDINARY validation hampers me. – Alexander Oct 21 '15 at 21:24
9

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