Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Practice for Lists of Complex Types in ASP.NET MVC 3

This is my first SO question, and it's less of a "how do I do this" and more of a "what is the cleanest way to do this", because there are several approaches I see but none of them seem very appealing to me.

This is a bit of a complicated issue to describe. Essentially, I have an Add/Edit view that allows the user to edit the fields of some object. This object is pretty complex: it has some fields, and it has a sub-list of complex objects. Each complex object is about 40 fields large (mostly checkboxes, radio buttons and dates/times). I have represented this as a select list:


(source: fortheloot.com)

The Add button spawns the dialog with the various fields.

The question comes here. When the user accepts the dialog, and the dialog closes, I now have to store this data somewhere, so that the user can edit it further or add other sub-items before actually submitting the form.

The most obvious way to do this is to create a set of hidden fields for every sub-object. So, adding a sub-item would add 40-something hidden elements to the <form> element. Add 10 sub-items and you have 400 hidden fields. This will work fine, and will bind to this model if the fields are named properly:

public class AddEditModel
{
  [Display(Name = "ID")]
  public int? Id { get; set; }

  [Display(Name = "Name")]
  [Required]
  [StringLength(100)]
  public string Name { get; set; }

  public IList<EntryModel> Entries { get; set; }
  public class EntryModel { /* fields */ }
}

On the model binding side of things, this seems to look pretty good, but from the client side, I'm having to keep track of hundreds of DOM elements and this seems cumbersome to me. Loading and unloading the dialog's various form elements from 40 other elements seems ... like it could be better.

Ideally, I'd like to be able to just store the data as a javascript object on the <option> element using either data- HTML 5 attributes or jQuery's data() function, which are really one and the same. This would make the javascript side of things much cleaner, but it wouldn't automatically bind to the model on postback.

If there was a way to have the best of both worlds -- storing a single JS object on the <option> element, or even a single <input type="hidden" /> element (per sub-item) -- that would still bind to the model properly on postback, I'd feel this issue resolved.

like image 576
John Hargrove Avatar asked May 05 '11 05:05

John Hargrove


1 Answers

You will still need an html field (type=hidden) in order to post this data back to the server. (You could use an ajax post but this probably isn't a great idea)

I would suggest designing a reasonable object model to contain these data structures, and serializing the object model each time you make a change it to json with stringify

Then when you post back the form, the json will be sent to the server and you can deserialise the whole object model to a set of classes written in c# (which can mimic the object model you had in javascript) using the JavaScriptSerializer classes

Edit:

To deserialize a json string, you can use the following code:

JavaScriptSerializer js = new JavaScriptSerializer(); 
var c = js.Deserialize<MyClass>(json);
return View(c);

If you post back json as the post message body, (e.g. an $.ajax, or $.post method) then binding will occur automatically with MVC3, you simply have to specify the correct content type: application/json in the post; follow the link in my comment below for more details as to how this works.

Martin

like image 66
Martin Booth Avatar answered Sep 28 '22 20:09

Martin Booth