1

I have an MVC 4 site I'm building that gets all it's data from a WCF service. I'm trying to be lazy and use the proxy classes generated in my WCF project in my MVC Models. So far so good.

I have a form view that takes in a Customer class that has a bunch of primitive typed properties and 3 generic lists (List) of other complex objects.

Everything works as expected with primitive types and I'm able to bind some of the fields in the form to the view and edit them. Great.

My issue is, when the Model is posted back to the form, The collections are always null, even if they were originally filled with objects.

Any idea why MVC wouldn't keep my sub collections in the model during Form post?

<!-- form -->
@using (Html.BeginForm("ourinformation", "Account", Model, FormMethod.Post, new{id= "contactForm" })){} 
Eric Langland
  • 95
  • 2
  • 10

1 Answers1

3

You need to post your collections back to your controller, so for example, say that you have the following classes, that you use as a model:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Group> Groups { get; set; }
}

public class Group
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Then say this is your how you pass the model to your view:

public ActionResult Index()
{
    var model = new User
    {
        Name = "Test",
        Groups = new List<Group>
        {
            new Group {Name = "GROUP1"},
            new Group {Name = "GROUP2"}
        }
    };
    return View(model);
}

And is how you're expecting it:

[HttpPost]
public ActionResult Index(User user)
{
    // do your thing ...
}

Your view should look something like:

<form action="/" method="post">
    <input id="Name" name="Name" type="text" value="Test" /><
    <input name="Groups[0].Name" type="text" value="GROUP1" />
    <input name="Groups[1].Name" type="text" value="GROUP2" />
    <input type="submit" value="Submit" name="Submit" />
</form> 

Now if you submit your model will be populated. You can of course use an editor template for the Group collection just create a view in EditorTemplates -> `/Shared/EditorTemplates/Group.cshtml' that contains the following:

@model MyApp.Models.Group
@Html.EditorFor(x => x.Name)

Now back in in your Index.cshtml, you can just do:

@model User
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Name)
    @Html.EditorFor(x => x.Groups)
    <input type="submit" value="Submit" name="Submit" />
} 

Here @Html.EditorFor(x => x.Groups) will iterate through your collection and create the necessary markup corresponding to the one in the Editor Template. I hope this helps.

Dimitar Dimitrov
  • 14,868
  • 8
  • 51
  • 79
  • Thanks for the detailed response. I'll give this a try and report back. One question. I do have some properties in the model that I am not linking to the form but those tend to get posted back to the controller still. Is it just sub-collections in the model that need this to be visible when posted? – Eric Langland Jan 06 '14 at 08:33
  • @user1851667 If you have missing properties in your model when posting back they won't prevent the binding of the rest. You can use only the ones you need. I hope I'm making sense. – Dimitar Dimitrov Jan 06 '14 at 08:56
  • --I'mn actually seeing things differently. My form uses a Model of Customer. Lets say that Customer has three properties. FirstName(string), lastName(string), CustomerID (int). If I generate a TextBoxFor m.FirstName and TextBoxFor m.LastName, when the form is posted to the controller, CustomerID is still available in the posted object, even though I didn't bind it in the form. Doe that make sense? – Eric Langland Jan 06 '14 at 19:00
  • ....and one more thing....I only need one field in the sub collection list of Customers. I only need CustomerID for each customer in the List<>. DO I have to created a HTML.EditorFor for every other property in the object for this to work? – Eric Langland Jan 07 '14 at 01:16
  • @user1851667 In regards to the CustomerID being bound without being on the form - not sure how that's possible, usually I'd have a `@Html.HiddenFor(x => x.CustomerID)`. – Dimitar Dimitrov Jan 07 '14 at 01:43
  • About your second question, nope you don't need to create an `EditorFor` for properties that you won't use for this to work. – Dimitar Dimitrov Jan 07 '14 at 01:46
  • As it turns out, specifying the Model in my BeginForm() statement is what's causing the non bound fields to be available. For example: – Eric Langland Jan 09 '14 at 22:07
  • So if I use the following form that includes the model, ALL fields are available on post. using (Html.BeginForm("ourinformation", "Account", Model, FormMethod.Post, new { id = "contactForm" })) If I remove the model in the form, I only get the fields that are bound in the view as you have suggested above. using (Html.BeginForm("ourinformation", "Account", FormMethod.Post, new { id = "contactForm" })) – Eric Langland Jan 09 '14 at 22:10