MVC loops within a View

Sometimes while programming, we find interesting things that although not necessarily obvious at the time of design, becomes quite obvious during implementation. That is what happened to me a few days ago.

Views and ForEach Loops

I was trying to implement a View that had a list of items. These items had data from several tables and needed to be editable. The first thing I did was write the  TextBoxFor items in a foreach loop because I tend to find it cleaner to write when applicable. The code would look something like the following:

@model IEnumerable<Person>

@using(Html.BeginForm())
{

foreach (var person in Model)
{

@Html.TextBoxFor(x => Model.FirstName)
@Html.TextBoxFor(x => Model.LastName)

}
}

.Now, you would think this would be ok, but there is one obvious problem that I for one didn’t think about. I think part of the reason is because we are getting used to the “syntactical sugar” and treat things sometimes too much “black box” for comfort. I always like to understand what is going on under the hood. To understand what is wrong here, you should probably know what’s under the hood, so lets code!

Views need For Loops, Not ForEach

There is a simple reason the foreach loop will not work. Think about it, when the form is submitted, before it reaches the controller the form data is rebound to the Model. This is why you have the option to either take in a parameter of FormCollection OR the object (in this case Person) into the action on the controller that is being sent the POST. So the above Code (assuming the View is called Index) would map to:

[HtmlPost]
public ActionResult Index(Person person)
{
// Do Stuff
}

If you do not understand the above code, please read some tutorials on MVC before continuing. Now, here is the question. If you use a foreach loop, how does the model binder know what textbox field goes to which object? The answer is it doesn’t. The above View code would render HTML similar to this assuming there were two Person objects:

<input type="text" id="FirstName" name="FirstName"/>
<input type="text" id="LastName" name="LastName"/>
<input type="text" id="FirstName" name="FirstName"/>
<input type="text" id="LastName" name="LastName"/>

This might make things a little clearer. Not only will this not work, but it completely violates the XML and W3C standards because all the inputs use the same name and id. So neither Javascript or .NET will be able to decipher one from the other.

Now lets try it with a for loop:

@model IEnumerable<Person>

@using(Html.BeginForm())
{

for (int counter =0; counter < Model; counter++l){

@Html.TextBoxFor(x => Model[counter]l.FirstName)
@Html.TextBoxFor(x => Model[counter].LastName)

}
}
This will render HTML like this:
<input type="text" id="FirstName[0]" name="FirstName[0]"/>
<input type="text" id="LastName[0]" name="LastName[0]"/>
<input type="text" id="FirstName[1]" name="FirstName[1]"/>
<input type="text" id="LastName[1]" name="LastName[1]"/>

Now we have (albeit just via index) different names for each field. Now the MVC Model Binder will be happy and you and I can go about our day!

Happy Coding Smile

Advertisements

About Gregg Coleman

I am Senior-level Software Engineer working primarily these days with .NET. I have a good working knowledge of ASP.NET MVC, Web Forms, WCF web services and Windows Services. I spend much of my time in the Web Services (SOAP and REST) world in my current job designing and implementing various SOA architectures. I have been in the software engineering industry for about 6 years now and will not now nor ever consider myself an "expert" in programming because there is always so much to learn. My favorite thing about designing software is there are always new emerging technologies and something to learn every day! My current job has me spending much of my job on the bleeding edge of technologies and changing gears all the time, so I'm never bored and always challenged. On my spare time I enjoy weight training, reading and venturing to new places near by. Of course programing and learning new technologies are another hobby of mine.
This entry was posted in .NET, .NET 4.5, ASP.NET, C#, Classes, Controllers, MVC, Validation, Views and tagged , , , , , , , . Bookmark the permalink.

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s