Unobtrusive validation not working on dynamically-added partial view
Asked Answered
T

2

47

I am currently facing a problem with validation after dynamically adding content.

I have a view strongly typed to a model (Order). This Order can have many items. The model looks something like the following:

public class Order
{
    [Key]
    [HiddenInput]
    public int id { get; set; }

    [Display(Name = "Order Number")]
    public string number { get; set; }

    [Display(Name = "Order Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
    public DateTime date { get; set; }

    [Required(ErrorMessage = "Beneficiary is required.")]
    [Display(Name = "Beneficiary")]
    public int beneficiary_id { get; set; }

    [Display(Name = "Beneficiary")]
    public Beneficiary beneficiary { get; set; }

    [Display(Name = "Items")]
    public List<Item> items { get; set; }

    [Display(Name = "Payment Method")]
    public List<PaymentMethod> payment_methods { get; set; }
}

I enter the order information and also the items for that specific order. I tried a couple of ways to add content dynamically and finally went with Steven Sanderson's way.

In my view, I have the regular Order information and then the items, where my model looks something like this:

@model trackmeMvc.Models.Model.Order
@{
    ViewBag.Title = "Create";
    Html.EnableClientValidation();
    Html.EnableUnobtrusiveJavaScript();
}

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

<script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/MicrosoftMvcValidation.js")" type="text/javascript"></script>

@using (Html.BeginForm("Create", "Order", FormMethod.Post, new { @id = "create_order" }))
    {
    @Html.ValidationSummary(true, "Order creation was unsuccessful. Please correct the errors and try again.")

    <div class="editor-label">
        @Html.LabelFor(m => m.date)<req>*</req>
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(m => m.date, new { @id = "order_date" })<br />
        @Html.ValidationMessageFor(m => m.date)
    </div>

...

<script type="text/javascript">

    $(document).ready(function () {

        $("#addItem").click(function () {

            var formData = $("#main_div").closest("form").serializeArray();

            $.ajax({
                url: "/IPO/BlankItemRow",
                type: "POST",
                //data: formData,
                cache: false,
                success: function (html) {
                    $("#editorRows").append(html);
                        //$.validator.uobtrusive.parseDynamicContent("form *");
                        //$("#editorRows").removeData("validator");
                        //$("#editorRows").removeData("unobtrusiveValidation");
                        //$.validator.unobtrusive.parse("#editorRows");
                        //$.validator.unobtrusive.parse("#create_ipo");
                        //$.validator.unobtrusive.parseDynamicContent($(this).first().closest("form"));
                        //$.validator.unobtrusive.parse($("#new_ipo_item"));

                        //$.validator.unobtrusive.parseElement($("#editorRows").find(".editRow:last").children().find("select"));
                           //$("#editorRows").find(".editRow:last").find("select").each(function () {
                           //alert($(this).attr("id"));
                           //$.validator.unobtrusive.parseElement($(this));
                           //$.validator.unobtrusive.parseDynamicContent($(this));
                           //$.validator.unobtrusive.parseDynamicContent($(this).attr("name"));
                       //});
                           //$("#editorRows").children().find(".editRows:last").find("*").each(function () {
                           //  alert($(this).attr('id'));

                           //$.validator.unobtrusive.parseDynamicContent('input');
                       //});
                       //var form = $(this).closest("form").attr("id");
                       //$(form).removeData("validator");
                       //$(form).removeData("unobtrusiveValidation");
                       //$.validator.unobtrusive.parse(form);
                    }
                });
            return false;
        });
    });

</script>

Those are some of the things I tried, and nothing works.

I got the parseDynamicContent from Applying unobtrusive jquery validation to dynamic content in ASP.Net MVC. I tried it in every scenario I could think of, but still no luck.

I also tried the regular parse, removing validation from the form then applying it again, but still the newly added elements are not validated:

<div id="editorRows">
    @foreach (var item in Model.items)
    {
        @Html.Partial("_NewItem", item)
    }
</div>

... and my partial view would look something like this:

@model trackmeMvc.Models.Model.Item 

@{
    Layout = "";    
    Html.EnableClientValidation(true);

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

<div class="editRow">

@using (Html.BeginCollectionItem("order_items"))
{

    @Html.DropDownListFor(m => m.item_id, @items, "None", new { @style = "width:205px;", @id = "ddlItems", @class="ddlItem", @name="ddlItemList" })
    @Html.ValidationMessageFor(m => m.item_id)

    ...

}

</div>

So what's happening is, I have one empty item sent from the controller to the view by default, to show one empty row. That item is validated, but whatever comes after when I click add item, another row appears, from that partial, but I can't get it to validate. I tried to put the validation in the partial view, (before the document ready in the main form), and everything I read I applied, and it always ends up the same: validating the first row, and not the others. I tried the validation of Steven Sanderson done for that purpose - still no luck - even the validation for partials, found at this link and the page that follows which is specific to partial validation...

What should I do to get this validation working?

Tusker answered 17/2, 2012 at 0:3 Comment(1)
possible duplicate of jquery.validate.unobtrusive not working with dynamic injected elementsChemisorb
G
101

Ok, I am going to start over with a new answer here.

Before you call $.validator.unobtrusive.parse, remove the original validator and unobtrusive validation from the form like so:

var form = $("#main_div").closest("form");
form.removeData('validator');
form.removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse(form);

This same answer is documented here.

Graig answered 17/2, 2012 at 7:0 Comment(11)
Hi and thanks for your reply. I am using MVC 3, and sorry about the "order_items" it's actually "items" just a typo. and the @items is a select list which i get from the database of all the items.. in the List<Item> items of the order class the all item properties are required, and what's happening is in my controller i put one empty item by default and that row is validated, on the client side. So i've replaced the script not to use the minified version as you suggested. Now i've checked and the data-val="true" and all that is being added to the dynamically added control.. Continued...Tusker
so when i try to remove unobtrusive validation it's gone, and when i try to put it back, it only validates the items that were at the fist page load, nothing that has been added dynamically.. i've tried to debug with chrome, but when i hit the $.validator.unobtrusive.parse($("#main_div").closest("form")); it goes to the end of the function the hits the script file "jquery-1.5.1.min.js" isn't it supposed to go to the validator script? i'm not too familiar with this chrome debugging thing.. but where can the missing link be? because when i remove validators and re-add them they go and work againTusker
which means that it's being called, but for some reason, it's not affecting the dynamically added content it's only validating all that was there to begin with before adding any controls.. so what could that be?Tusker
I put the breakpoint there as you said, and i checked, it's running over the elements that have been dynamically added as well, it's not working tho?? what's the deal?Tusker
I have used your code to build a similar scenario, and the validation is working for me. There must be something else you are missing. Does the Chrome debugger report any errors?Graig
it's driving me crazy, i can't figure out what the problem is.. i read somewhere that once the validation is bound to the form it cannot be bound again, so u will have to unbind then rebind it.. however i did that as well and still no luck..Tusker
hello, i'm still stuck on this issue. can you please send me your working example and i'll try to work around it? noobibox at gmail.. i would really appreciate it. Thanks.Tusker
that is actually what it takes, not sure what i was doing wrong but starting from scratch and doing this in a newly created sample worked for me!! thanks a ton!Tusker
Your solution helped me in combination with this solution #6466330Littell
This worked for me after few yours of debugging my MVC solution. Thanks!Wideawake
This worked for me -- I was trying .parse() after the first .parse() and it wasn't working; with your solution (removing the first validation) worked like a charm.Ginter
L
4

What worked for me was to re-apply the validator after the call to load the partial view. In my case, I'm using $.post().then() but you could do something similar with a .always() callback of an AJAX call.

$.post(url, model, function (data) {
    //load the partial view
    $("#Partial").html(data);
}).then(function () {
    $("form").each(function () { $.data($(this)[0], 'validator', false); });
    $.validator.unobtrusive.parse("form");
});
Lipps answered 15/3, 2018 at 22:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.