Editing Collections in ASP.NET MVC

A recent comment on one of my earlier articles got me thinking again about ASP.NET MVC model binding and validation. The comment was from Bart Calixto, and was to the effect that my concern over MVC validation and repeating forms was misplaced – that simply binding to a collection meant that MVC could handle this itself.

My immediate response was that the problem remains – that by default MVC does not generate unique IDs for repeating forms and creates malformed HTML (and causes issues with client-side validation). However – Bart is right that it is possible to get MVC to manage the client-side IDs properly by binding to a collection. So why don’t I go down that route? Because the price of fixing the client-side IDs/validation is that the server-side model binding relies upon a single form  containing the main object and the collection(s) associated with it. My design used small repeating forms, one for each collection item (I was using a lot of Ajax and wanted to pass as little data as possible between server and client). Collection binding would solve the client-side problems I highlighted, but only at the cost of breaking the server-side model binding. Still – I think it’s worth looking at the alternative approach and seeing what it does for us – and what it doesn’t.

In order to bind a collection of complex objects, you need to set up editor templates and call them inside a for loop in the view.

So – first, what is an editor template?

Normally you call EditorFor() on simple data and get a standard HTML widget. Assigning EditorFor() to a string property will automatically generate a text input:

This code:

temp

Gives us this output:

However, we can create a view that contains many such elements and is designed to be the editor for a more complex object. In this case, I want to edit a Player object from my HTML5 game LaLaLadders. The first thing I need to do is add a new folder EditorTemplates under the Shared folder.

Like so much else in MVC, you use conventional names and locations to tell the system what to do. The next step is to add a view called Player[.cshtml/.vbhtml] underneath the folder:

Inside the file, add in the appropriate markup:

Now all we need to do is point the individual Player objects at this template inside a for loop in the main edit view and tell EditorFor() which template to use:

This then generates a form with all the players:

And each Player is given a unique id and name:

And these work perfectly well with client-side validation:

And the complex object is bound appropriately on the server:

So why does this not solve my problem?

The answer lies in the little ‘save’ button sitting after each individual player. It is completely redundant, because there is only one form. When I save, I am saving everything. But that’s not what I want. What I want – and what I have in the actual application – is repeating forms. I want to edit JUST the individual Player‘s details, not the whole object. I don’t want to be sending all that data back to the server – just the little bit I need.

So, no problem you might think. Just have the Player editor template contain a form that posts to a separate EditPlayer method and bind a single Player. Okay, let’s try that…

First, we have to move our iterator out of the main form so we don’t end up with nested forms:

Then we need to amend the Player editor so it contains a form that posts to EditPlayer:

We run it, and everything looks good. We end up with individual forms, each of which has the same iterated IDs and Names – e.g. Players_2_Name and Players[1].Name.

And that’s where we hit the problem. The model binder was fine with those names when it was dealing with the Players collection – but not now that we’re dealing with an individual Player. The result is our model is not bound on the server:

So, although you can get MVC to sort out its issues with client-side IDs and validation, you might not always want to. Sometimes, the cure can be worse than the disease. My LaLaLadders application would have been much more complicated, and would have used a heck of a lot more bandwidth, if I’d gone down this path… which is not to say that it isn’t the right solution in most circumstances.

The conclusion of all this? I still don’t think MVC handles repeating forms very well, but it does have some good tools for handling collections within a single form, if that’s what you’re looking for.

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC




Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

%d bloggers like this: