9

Hi I'm prototpying an ajax wizard with MVC 3 (razor). An oddity I've notice is when you return a partial view to UpdateTargetId plugs the view in but doesn't add/apply the Unobtrusive JavaScript. If I load the partial view outside the ajax block e.g.

@Html.Partial("Company")

It works perfectly so I'm not missing any of the standard libraries and My web config is all good.

So at the moment I'm little stumped.

My view is the following:

@using(Ajax.BeginForm("Step", "Origination", new AjaxOptions { UpdateTargetId = "stepArea" })){

    <div id="stepArea"></div>
   <input id="btnSubmit" type="submit" value="submit" />
}

Controller:

public ActionResult Step(FormCollection formCollection)
{
    if (this.Request.IsAjaxRequest())
    {
        switch ((TempData["step"] as string))
        {
            case "Company":
                TempData["step"] = "Person";
                return PartialView("Company");

            case "Person":
                TempData["step"] = "Pay";
                return PartialView("Person");

            case "Settlement":
                return PartialView("Pay");

            default:
                TempData["step"] = "Company";
                return PartialView("UserType");
        }
    }
    return View();
}

My Question is can the validation from the partial view be initalised/implemented from the partial refresh?

Nickz
  • 1,880
  • 17
  • 35

3 Answers3

10

After reading a few forums and doing some experiments. the final piece of the puzzle, causing the validation to work after returning a partial view. jquery.validate.unobtrusive not working with dynamic injected elements

<script type="text/javascript">

    function validateAjaxForm() {
        $("form").removeData("validator");
        $("form").removeData("unobtrusiveValidation");
        $.validator.unobtrusive.parse("form");
        return $('#form').valid();
    }
</script>


 @{ Html.EnableClientValidation(true); } 
@using (Ajax.BeginForm("Step", "Origination", new AjaxOptions { UpdateTargetId = "stepArea", OnBegin = "return validateAjaxForm();" }, new { id = "form" }))
{
    <div id="stepArea"></div>
    <input id="btnSubmit" type="submit" value="submit" />
}

works perfectly.

Community
  • 1
  • 1
Nickz
  • 1,880
  • 17
  • 35
  • Unfortunately there is a major issue with that solution -- please take a look at my answer. – chris Apr 12 '13 at 12:06
9

Try initializing FormContext if it is null in your view. This should add unobtrusive validation "data-val-*" attributes to generated controls

@{
    if (Html.ViewContext.FormContext == null)
    {
        Html.ViewContext.FormContext = new FormContext();
    }
}
archil
  • 39,013
  • 7
  • 65
  • 82
  • 3
    Cheers its added the unobtrusive data-val-*. Now I need to find a way to make the validation trigger by ajax.beginform submit action. strangely the validation isn't triggering. – Nickz Jul 26 '11 at 01:12
0

There is a big problem with Nickz solution, which made me pull my hairs out until I found a different workaround.

    // forces creation of a new validator, which in turn causes 
    // an extra submit event handler to be attached!!!
    $("form").removeData("validator");
    $("form").removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse("form"); 

When you do that, every time you call $.validator.unobtrusive.parse(), a new event handler will be attached to the form's submit event, while leaving the old event handler intact. This means that when you run the above code multiple times, the validator will unnecessarily run multiple times when the submit event is fired. This caused severe performance problems for me. So I ended up writing a custom alternative to the parse() method which I named updateParse:

    $.extend($.validator.unobtrusive, {
    updateParse: function (selector) {
        /// <summary>
        /// Custom alternative for the built in method $.validator.unobtrusive.parse() which can updates an existing validator.
        /// Use this only when a validator has not yet been initialized, i.e. when $.validator.unobtrusive.parse()
        /// has not yet been called before.
        /// This is intended for use after you dynamically add / remove / modify validatable elements to a form via AJAX.
        /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
        /// with the [data-val=true] attribute value and enables validation according to the data-val-*
        /// attribute values.
        /// </summary>
        /// <param name="selector" type="String">Any valid jQuery selector.</param>
        var $forms = $(selector)
            .parents("form")
            .andSelf()
            .add($(selector).find("form"))
            .filter("form");

        $(selector).find(":input[data-val=true]").each(function () {
            $.validator.unobtrusive.parseElement(this, true);
        });

        $forms.each(function () {
            var form = $(this);
            var info = form.data("unobtrusiveValidation");
            if (info) {
                var validator = form.data("validator");
                if (validator) {
                    validator.settings.rules = info.options.rules;
                }
                else {
                    throw "validator not yet initialized for this form yet -- use $.validator.unobtrusive.parse() instead";
                }
            }
        });
    }

This will update the validation rules of the existing validator object, instead of forcing the creation of a new validator while adding an extra submit event handler. In my option, the parse() method should just work when a validator already exists.

chris
  • 2,541
  • 1
  • 23
  • 40