-1
public PersonViewModel()
    {
        Children = new List<ChildViewModel>();
    }

    [Required(ErrorMessage = "Required!")]
    public string FName { get; set; }

    [Required(ErrorMessage = "Required!")]
    public string LName { get; set; }

    public List<ChildViewModel> Children{ get; set; }
 }

    public class ChildViewModel
 {
    [Required(ErrorMessage = "Required!")]
    public string FName { get; set; }

    [Required(ErrorMessage = "Required!")]
    public int Age { get; set; }
 }

my controller

    public ActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public ActionResult Index(PersonViewModel person)
    {
        if (!ModelState.IsValid)
        {
            return View(person);
        }
        return View();
    }
    public ActionResult AddChildBox(PersonViewModel person,int id)
    {
        ViewBag.Counter = id;
        return PartialView("View");
    }
 }

I am calling partial view through ajax to create fields for child

    <script type="text/javascript">
    var num = 0;
    $("#AddChildBtn").click(function () {

        $.ajax({
            type: 'GET',
            url: '@Url.Content("~/Home/AddChildBox/")',
            data: {
                Id: num

            },
            dataType: 'html',
            success: function (result) {
                $('#Fields').append(result);
                num = num + 1;
            }
        });
    });
 </script>

in view show Children with this code

 @if (Model != null )
 {
    for (int i = 0; Model.Child.Count>i;i++ )
    {
        @Html.Action("AddChildBox", "Home", new { id = i })
    }
 }

and my partial view

@model WebApplication4.Models.PersonViewModel

@{
    int i = ViewBag.Counter;
}
<div class="form-group">
    @Html.LabelFor(model => model.Child[i].FName, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Child[i].FName, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Child[i].FName, "", new { @class = "text-danger" })
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.Child[i].Age, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Child[i].Age, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Child[i].Age, "", new { @class = "text-danger" })
    </div>
</div>

This works, but when delete person from AddChildBox action method parameters, Validation messages for partial view fields not work. I do not use it in my action , So why do I need it? I am confused , who can explain to me what happen in this code?

teo van kot
  • 12,350
  • 10
  • 38
  • 70
ramin_rp
  • 321
  • 1
  • 4
  • 14
  • When you submit, is your ChildViewModel list empty? Your partial has no idea about your original model, so it is creating a new one. You can make your Children be an array of ChildViewModel and then in your partial, just do ` `. When you submit, your model will now have an array of children. – Jacob Roberts May 11 '15 at 21:16

1 Answers1

2

There are a number of issues with your implementation. The reason you will not get validation for dynamically added content is the the validator is parsed when the view is first rendered and knows nothing of the new content. You need to re-parse the validator after you have appended the new content using

$('form').data('validator', null);
$.validator.unobtrusive.parse($('form'));

Your partial view will not give true 2-way model binding and I recommend you use the BeginCollectionItem helper to render a partial for each item (refer this article for an example). The helper replaces the zero-based indexers with a Guid and renders an additional hidden input for a matching Index value that allows non consecutive indexed collections to be successfully bound (i.e. allow you to dynamically delete items in the view).

A pure client side alternative is shown in this answer.

Community
  • 1
  • 1