client side validating dynamically generated form

2019-07-25 04:01发布

问题:

I have read a lot about how to validate dynamically generated content in mvc 3.0 such as the one xhalent has written , But I cant understand how to use it in my code. I mean it does not work for dynamically generated form elements. Here is my Model classes:

 public class Person
{
    [Required]
    public string Name { get; set; }

    [Required]
    public string Phone { get; set; }

    public IList<Address> Addresses{get;set;}

    public Person()
    {
        Addresses = new List<Address>()
                            {
                                new Address(){Street="1"},new Address(){Street="2"}
                            };
    }


}

public class Address
{
    [Required(ErrorMessage="Error")]
    public string Street { get; set; }
}

And this the view in which the form is begin displayed:

<script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript"></script>
<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>

<% using (Html.BeginForm())
       { %>
    <%: Html.ValidationSummary(true) %>
    <fieldset>
        <legend>Person</legend>
        <%: Html.EditorForModel() %>
            <div class="phone-numbers">
                <%
           foreach (var item in Model.Addresses)
       {

            %>
            <%Html.RenderPartial("EditorTemplates/Addresses", item);%>
            <%} %>
        </div>

    <div style="padding: 10px 0px 10px 0px">
        <a id="add-phone" href="javascript:void(0);">Add another</a>
    </div>
    <input type="submit" value="Create" />
</fieldset>
<% } %>
</div>

  $().ready(function () {
             $("#add-phone").click(function () {
                 $.ajax({
                     url: '<%: Url.Action("GetNewAddress") %>',
                     success: function (data) {
                         $(".phone-numbers").append(data);                   
                    }
                });
            });
        });

And this is the partial view for Address:

<div style="padding: 5px 0px 5px 0px" name="editorRow" id="editorRow">
        <%: Html.LabelFor(m => m.Street) %>
        <%: Html.EditorFor(m => m.Street)%>
        <%:Html.ValidationMessageFor(m=>m.Street) %>
    </div>

回答1:

First, if your partial view, add this at the top

<%
 if (Html.ViewContext.FormContext == null)
    {
        Html.ViewContext.FormContext = new FormContext();
    }
%>

This should add unobtrusive data-val-* validation attributes to generated content. And in your success function of ajax downloading, insert this at the end

 $().ready(function () {
             $("#add-phone").click(function () {
                 $.ajax({
                     url: '<%: Url.Action("GetNewAddress") %>',
                     success: function (data) {
                         $(".phone-numbers").append(data);      

                         $("form").removeData("validator");
                         $("form").removeData("unobtrusiveValidation");
                         $.validator.unobtrusive.parse("form"); 

                    }
                });
            });
        });

This time it should automatically parse the downloaded content and apply validations to it

I took a look at your project and found the reason of dynamic validation not working. Practically you've got more problems in there than the validation. First, the technique you use for rendering addresses is not correct. That way, all the inputs you generate have the same id and name values. That's the reason why validator cannot distinguish between dynamically added content and previous one, it thinks all the inputs are the same and validates all streets according to first street. And moreover, if you posted that content to create on server, asp.net mvc model binder could not have binded the array of streets - for the same reason why validator cannot work. Take a look at this article for proper generation of list contents on client side. And for later, dynamic injection, you can change the controller code like

public ActionResult GetNewAddress(string id)
        {
            ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("[{0}]", id);
            return View("EditorTemplates/Addresses", new Address());
        }

Passing correct id from client side is up to you :).

Also, you do not use EditorTemplates correctly, they are meant to be used with Html.DisplayFor(), and you should not have to specify their name by hand. Read about them more, there're dozens of articles there on the web