So I’m working on an Advert listing page where I need to allow the user to add rooms to an advert dynamically without posting back the page. I want to do this with Ajax to reduce the amount of navigation required thus improving the UX.
Initially I looked at using the Ajax helper methods to load the dynamic elements of the page. However, this didn’t work so well since MVC/HTML doesn’t support nested forms.
Ajax.BeginForm inside Html.BeginForm
I ended up using some JQuery to load the rooms and Add/Remove rooms. The JQuery calls an action on the controller to load the rooms after adding/removing the rooms.
$("[name='RemoveRoom']").click(function () {
var url = $(this).data('url');
$('#roomsWrapper').load(url);
});
[HttpGet]
public ActionResult GetRooms(int Id)
{
var viewModel = this.roomAvailableAdvertStore.FindById(Id);
return PartialView("_Rooms", viewModel.Rooms);
}
The problem I’m now facing is that these dynamically loaded elements are not being bound to the View Model when I submit the form. To explain more clearly
<form>
@Html.HiddenFor(m => m.AdvertId);
<div id=”roomsWrapper”>
// These data items are not being bound to the model.
@Html.Partial(“_Rooms”, Model.Rooms);
</div>
<input type="submit" />
<form>
_Rooms.cshtml partial page looks like this:
@model List<RoomViewModel>
@for (int roomIndex = 0; roomIndex < Model.Count(); roomIndex++)
{
@Html.HiddenFor(m => m[roomIndex].RoomId)
}
The form posts back to an action with the following signiture:
public async Task<ActionResult> Update(RoomAvailableAdvertViewModel model)
{
...
}
The view model looks like this:
public class RoomAvailableAdvertViewModel
{
public int AdvertId { get; set; }
public List<RoomViewModel> Rooms { get; set; }
}