ASP.NET MVC – Model binding not occurring when posting list of complex types

Some background – I am turning a gigantic Word form into an MVC application where each ‘page’ represents a small section of that form, and I had some trouble posting the model back to be saved. Lists of complex types – in my example, List – were coming back as null.

I have a class called Section.cs:

public class Section
    {
        public string SectionName { get; set; }
        public List<Field> SectionFields { get; set; }
    }

Each section can have any number of Field objects – and each field has a value (this example has been simplified; the actual model has a lot more properties):

public class Field
    {
        public string Value { get; set; }
    }

I created a view for my Section with a form. The SectionName property is just a string, so you can just call:

@html.EditorFor(model => model.SectionName)

MVC knows how to deal with a String, and will return the appropriate form input (you can, of course, create your own Editor Templates for simple types).

Field, on the other hand, is a complex type – and the best way to deal with complex types is to create a custom Editor Template (this is done by creating a partial view under /Views/EditorTemplates with the same name as your complex type):

@model Field

<label class="radio-inline">
    @html.LabelFor(x => x.Value)
    @html.TextBoxFor(x => x.Value)
</label>

In my Section view, I iterated over my list of Field objects and called @html.EditorFor() on each, knowing that I had an Editor Template set up.

@model Section

@html.EditorFor(model => model.SectionName)

@foreach(Field field in model.Fields)
{
@html.EditorFor(f => field)
}

I got a label and a textbox for each field in my list – but when I tried to post my form, the Fields object was always null.

It turns out (thank you http://stackoverflow.com/a/9143266/3257985) that the default MVC model binder makes it much simpler. Rather than iterating over the list of Field objects, I can just do:

@model Section

@html.EditorFor(model => model.SectionName)

@html.EditorFor(model => model.Fields)
}

If you look at the generated html for the Value property of each Field object, you will see why this works. Iterating over the list of fields produced this value for the input’s name attribute:

Section.field.Value

The model binder relies on the input’s name to work out what to do with the value – and this does not tell the model binder enough. It will find the Section object, but there is no such thing as ‘field’ (which comes from the use of ‘field’ here: @html.EditorFor(f => field)

This is what the name attribute looks like on the example that works:

Section.Fields[0].Value

The model binder can work out that you are targeting the Value property on the first object in the Fields list on the Section object. Model binding will work, and your complex type will be posted.

7 comments

  1. I am trying to understand this and I believe you need to rename all the code blocks that reference “model.fields” with model.SectionFields
    then the very last code block becomes: Section.SectionFields[0].Value

    ..or am I way off?

    I am dealing with a similar issue and still struggling to make the model binding work.
    I am about to rip out the relevant code and make a really simple project just to prove it all out.

  2. I finally solved my problem, and in the off chance it may help someone else…
    { get; set; } on the list is super important 🙂

    my model class was defined like so:
    public List SectionFields = new List();

    changed to:
    public List SectionFields { get; set; }

    now the data is coming back from the controller and it makes total sense now why it didn’t before.

    1. This is an old post, but right now I’m in love with you!! Being trying to find why my model didn’t bind correctly and this was it.

  3. Hi!!! I’ve got something like that BUT my template has fields that user should fill, but those new values doesn’t go to my controller, after post. Do you have any idea?

    thanks for your post, really helped me a lot

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s