title: MVC Model Binding with Dynamic Collection
body: <p>According to the seminal Scott Hanselman article on the complexities of the <a href="http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx" rel="noreferrer">ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries</a>:</p>
  
  <blockquote>
    <p>We read in the properties by looking for <strong><code>parameterName[index].PropertyName</code></strong><br>
    The index must be zero-based and unbroke</p>
  </blockquote>
  
  <p>So this HTML:</p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;input type=&quot;text&quot; name=<b>&quot;People[0].FirstName&quot;</b> value=&quot;George&quot; /&gt;
  &lt;input type=&quot;text&quot; name=<b>&quot;People[1].FirstName&quot;</b> value=&quot;Abraham&quot; /&gt;
  &lt;input type=&quot;text&quot; name=<b>&quot;People[2].FirstName&quot;</b> value=&quot;Thomas&quot; /&gt;
  </code></pre>
  
  <p>Which will post like this:</p>
  
  <p><img src="https://i.stack.imgur.com/ou0VH.png" alt="Post Data - People%5B0%5D.FirstName=George&amp;People%5B1%5D.FirstName=Abraham&amp;People%5B2%5D.FirstName=Thomas"></p>
  
  <p>However, if I load a new person into my model over AJAX, I lose the context for building that person into the model and get the following output:</p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;input type=&quot;text&quot; name=<b>&quot;FirstName&quot;</b> value=&quot;New&quot; /&gt;
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/PcE5l.png" alt="Post Data - People%5B0%5D.FirstName=George&amp;People%5B1%5D.FirstName=Abraham&amp;People%5B2%5D.FirstName=Thomas&amp;FirstName=John"></p>
  
  <p>Which won't get picked up by the model binder.</p>
  
  <p><strong>Q</strong>: <em>How can I preserve the expression tree when dynamically adding new elements over AJAX?</em></p>
  
  <h3>Here's an MVCE</h3>
  
  <p><strong>Model: <code>/Model/Person.cs</code></strong></p>
  
  <pre class="lang-cs prettyprint-override"><code>public class PersonViewModel
  {
      public List&lt;Person&gt; People { get; set; }
  }
  public class Person
  {
      public String FirstName { get; set; }
      public String LastName { get; set; }
  }
  </code></pre>
  
  <p><strong>Controller: <code>Controllers/PersonController.cs</code></strong></p>
  
  <pre class="lang-cs prettyprint-override"><code>[HttpGet]
  public ActionResult Index()
  {
      List&lt;Person&gt; people = new List&lt;Person&gt; {
          new Person { FirstName = "George" , LastName = "Washington"},
          new Person { FirstName = "Abraham" , LastName = "Lincoln"},
          new Person { FirstName = "Thomas" , LastName = "Jefferson"},
      };
      PersonViewModel model = new PersonViewModel() {People = people};
      return View(model);
  }
  
  [HttpPost]
  public ActionResult Index(PersonViewModel model)
  {
      return View(model);
  }
  
  public ActionResult AddPerson(String first, String last)
  {
      Person newPerson = new Person { FirstName = first, LastName = last };
      return PartialView("~/Views/Person/EditorTemplates/Person.cshtml", newPerson);
  }
  </code></pre>
  
  <p><strong>View: <code>Views/Person/Index.cshtml</code></strong></p>
  
  <pre class="lang-html prettyprint-override"><code>@model PersonViewModel
  
  @using (Html.BeginForm()) {
      &lt;table id="table"&gt;
          &lt;thead&gt;
              &lt;tr&gt;
                  &lt;th&gt;@Html.DisplayNameFor(model =&gt; model.People.First().FirstName)&lt;/th&gt;
                  &lt;th&gt;@Html.DisplayNameFor(model =&gt; model.People.First().LastName)&lt;/th&gt;
              &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
              @for (int i = 0; i &lt; Model.People.Count; i++)
              {
                  @Html.EditorFor(model =&gt; model.People[i])
              }
          &lt;/tbody&gt;
      &lt;/table&gt;
  
      &lt;input type="button" value="Add Person" id="add"/&gt;
      &lt;input type="submit" value="Save" /&gt;
  }
  
  &lt;script type="text/javascript"&gt;
  
      $("#add").click(function() {
          var url = "@Url.Action("AddPerson")?" + $.param({ first: "", last: "" });
          $.ajax({
              type: "GET",
              url: url,
              success: function(data) {
                  $("#table tbody").append(data);
              }
          });
      });
  
  &lt;/script&gt;
  </code></pre>
  
  <p><strong>View: <code>Views/Person/EditorTemplates/Person.cshtml</code></strong></p>
  
  <pre class="lang-html prettyprint-override"><code>@model Person
  
  &lt;tr&gt;
      &lt;td&gt;@Html.EditorFor(model =&gt; model.FirstName)&lt;/td&gt;
      &lt;td&gt;@Html.EditorFor(model =&gt; model.LastName)&lt;/td&gt;
  &lt;/tr&gt;
  </code></pre>
  
  <p><strong>NOTE</strong>: There are other complexities when deleting an item that I'm not looking to address here per se.  I'd just like to add an element and know that it belongs in a nested context alongside other properties.</p>