0

The default model binder is not mapping the collections in my model. Here is my code:

Model:

public class Company
{
   public string Name;
   public List<CompanyActivity> Activities
}

public class CompanyActivity
{
   public string  Code;
   public string Description
}

Controller:

[HttpPost]
public ActionResult Index(Company company) {}

View/HTML:

<input name="Name" type="text" value="some name" />
<input name="Activities[0].Code" type="text" value="1" />
<input name="Activities[0].Description" type="text" value="a" />
<input name="Activities[1].Code" type="text" value="2" />
<input name="Activities[1].Description" type="text" value="b" />

The Name input is mapped but the Activities list is empty.

1
  • The HTML you've given shows the value="" attribute as empty. What happens when you provide values? Also, what is your MVC view source? Commented Jan 16, 2014 at 8:14

3 Answers 3

1

You have defined your model with fields, but you have to use properties. You only have to change your model for this:

public class Company
{
    public string Name { get; set; }
    public List<CompanyActivity> Activities { get; set; }
}

public class CompanyActivity
{
    public string Code { get; set; }
    public string Description { get; set; }
}

Differences between fields and properties: Difference between Property and Field in C# 3.0+ and ASP.net MVC - Model binding excludes class fields?

Sign up to request clarification or add additional context in comments.

2 Comments

why? I have created a proyect with your code. Without properties dont bind and with properties bind properly. The HTML is right, like I said I have only added the {get;set;} and it works fine.
Interesting I didn't realize the modelbinder was smart enough to do this using that name syntax. My answer is not nearly as neat in comparison.
0

The names need to be identical for it to build them as a collection/array:

I would create a ViewModel to handle this case, this is why I almost always build a ViewModel to handle view rendering and the idiosyncrasies of MVC.

Model

public class Company
{
   public string Name;
   public List<CompanyActivity> Activities
}

ViewModel

public class CompanyViewModel
{
   public string Name;

   //View specific
   public List<int> CompanyActivityCodes
}

View

<input name="Name" type="text" value="" />
<input name="CompanyActivityCodes" type="text" value="" />
<input name="CompanyActivityCodes" type="text" value="" />

This will then bind the CompanyActivityCodes property, you can then reassign these to build up the Activities property in the controller.

public ActionResult Index(CompanyViewModel companyViewModel) 
{
  var company = new Company { Name = companyViewModel }; 
  company.Activities = companyViewModel.CompanyActivityCodes.Select(x =>  new CompanyActivity { Code = x });
}

3 Comments

I have updated my code. Activities is a list of objects, not a list of ints.
yes but it's not that clever where it can figure out the nested properties when using collections.
I understand, the modelbinder is not advanced enough however to figure out the nested properties when working with collections. For this reason I created a ViewModel which essentially "flattens" you CompanyActivity class into a flat class. As you see I have named the property CompanyActivityCodes as it flattens the code property in the activities collection. You've edited the question to include additional properties which complicates matters.
0

it shoould be

<input name="company.Activities[0].Code" type="text" value="" />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.