chrism233 chrism233 - 1 month ago 18
Ajax Question

Post an ASP.NET MVC page partially loaded with JQuery

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; }
}

Answer

I managed to solve this issue thanks to the links left in the comments.

Basically this issue occurs because the default ASP.net MVC model binder is only able to bind to a collection of complex types if they can be uniquely identified. This is all explain far more articulately by Phil Haack in the following article:

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

However, the limitation with Phil’s approach is that he applies a numeric index to each element in the collection. This approach fails when you attempt to add items dynamically, as the index won’t be unique. The second link given in the comments solves this problem by applying a Guid to each element in the collection, ensuring that each element in the collection has a unique key.

http://blogs.interknowlogy.com/2014/08/01/mvc-series-part-1-dynamically-adding- items-part-1/

It would be interesting if the Razor view engine could be extended to mitigate this issue occurring.