I am not entirely sure the best way to ask but, but I am looking for the "proper" way to deal with posting back a dynamic complex view model back to a view via ajax submit. I feel like it's been gone through before but I can't seem to find a good example here
A quick simple example to go off of. Lets say I have the following View Model:
public class PersonViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public Gender Gender{ get; set; }
public List<PhoneNumberViewModel> PhoneNumbers { get; set; }
}
With PhoneNumberViewModel like so:
public class PhoneNumberViewModel
{
public string PhoneNumber { get; set; }
public string Extension { get; set; }
}
The form is just a form that displays the persons information with their phone numbers. They can add or remove phone numbers.
All of this is in a simple form like so:
<form id="personForm" action="@Url.Action("Person", "Home")" method="post">
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.Id)
@Html.LabelFor(model => model.FirstName, "First Name")
@Html.TextBoxFor(model => model.FirstName, new { @class = "form-control"})
@Html.LabelFor(model => model.LastName, "Last Name")
@Html.TextBoxFor(model => model.LastName, new { @class = "form-control"})
@Html.LabelFor(model => model.Gender, "Gender")
@Html.EnumDropDownListFor(model => model.Gender, new { @class = "form-control"})
@Html.LabelFor(model => model.DateOfBirth, "Date Of Birth")
@Html.TextBoxFor(model => model.DateOfBirth, new { @class = "form-control", type = "date"})
<table class="table table-striped">
<thead>
<tr>
<th>Extension</th>
<th>Phone Number</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.PhoneNumbers.Count; ++i)
{
<tr>
<td>@Html.TextBoxFor(model => model.PhoneNumbers[i].Extension)</td>
<td>@Html.TextBoxFor(model => model.PhoneNumbers[i].PhoneNumber)</td>
</tr>
}
</tbody>
</table>
<button type="submit" id="savePersonForm" class="btn btn-success">Submit</button>
With a simple post like so:
var serializeForm = $("#personForm").serialize();
$.ajax({
url: action,
method: 'post',
contentType: "application/x-www-form-urlencoded",
data: serializeForm
}).done(function (response) {
// handle response
}).fail(function () {
// handle error
});
This works just fine, except this requires a constant maintenance of updating the fields name index's so that it will bind correctly to the controller method. If not PhoneNumbers will come back as null inside of the PersonViewModel when it is bound the controller method. Also using a foreach loop instead of a for will also not bind PhoneNumbers in the PersonViewModel to the controller method as you are not keeping up with the index values.
Is this really the way people constantly handle this in MVC to get it to bind correctly? To always make sure your javascript updates the name value index's if you remove and/or add a row, and make sure you keep the javascript up to date with the information inside of the view model, as it is possible more properties could be added or removed later? To me this feels like an "old" way of having to handle this.
Thanks!