views:

965

answers:

4

I have a form which contains a whole heap of data entry fields that will be completed by the user including some elements where the user can dictate how many of the same items they will enter. This is as is being used in Phil Haack's blog entry Model Binding To A List.

I am successfully using JQuery to create the extra form elements, correctly indexed, etc. My issue is the best way to actually read these within my Controller. The Controller in the article only expects one object, IList<Product> whereas my Controller already expects a FormCollection form and now I am trying to also send it an IList<Itmes> as well.

Should I be adding this to the parameters expected by the Controller or accessing via form["items"] or something else?

View

<form action="/MyItems/Add" method="post">
   <input type="text" name="Title" value="" />

   <input type="hidden" name="myItem.Index" value="0" />
   <input id="item[0].Amount" name="item[0].Amount" type="text" value="" />
   <input id="item[0].Name" name="item[0].Name" type="text" value="" />

   <input type="hidden" name="myItem.Index" value="1" />
   <input id="item[1].Amount" name="item[1].Amount" type="text" value="" />
   <input id="item[1].Name" name="item[1].Name" type="text" value="" />
</form>

Controller

public ActionResult Add(FormCollection form)
{
    string Title = form["Title"];
    List<Item> Items = form["items"].ToList();
}

DTO

public class Item()
{
    int Amount {get; set; };
    string Name {get; set; };
}
+1  A: 

You could just add the myItem as a parameter like so:

public ActionResult Add(FormCollection form, List<Item> myItem)
{
}

It will then bind automatically from the form data and populate the myItem parameter.

Schotime
I'll give that another go. I tried that but kept getting a "Object reference not set to an instance of an object." error so assumed that it would not bind automatically if I was also using FormCollection.
dave
That's Perfect! Impossible to be easier :)
ludicco
A: 

I have decided to work with exclusively with the FormCollection rather than muddying the waters with some data being passed through using FormCollection and other data being mapped to a List by the framework. The below code takes the items and hydrates the DTO manually. This works nicely and allows me to do some other things within my code that were not possible mapping directly to a List.

List<Item> itemList = new List<Item>();
int i = 0;

while ( form["item[" + i + "].Amount"] != null)
{
    itemList.Add(new Item()
        {
            Amount = Convert.ToInt32(form[String.Format("item[{0}].Amount",i )]),
            Name = form[String.Format("item[{0}].Name",i )]
        });
}
dave
A: 

I haven't tried this so you'll have to give it a go, but why not use the UpdateModel or TryUpdateModel method? This should bind in the same way as passing the IList into the controller's action.

That is:

public ActionResult Add(FormCollection form)
{
    List<Item> items = new List<Item>();
    TryUpdateModel(items, form);
}

I'm not at my development computer, so I'm not sure that it'll work, but I expect it should. Let me know if it's what you need.

EDIT: It's worth noting that if you're using the entity framework, I have come across many problems with the UpdateModel methods and have resorted to writing my own.

Odd
A: 

Scott Hanselman has a blog post related to this.

Phil Haack's blog post is very useful when posting lists too (as mentioned in the original question.)

Drew Noakes