Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Html.DropDownListFor Basic Usage

I'm just starting to learn MVC4 and I must admit I'm a little challenged by all the reliance on lambda expressions, generics and anonymous types, especially when there are many overloaded functions. It's a bit confusing to try and understand how the HTML Helpers work. Take the "DropDownListFor" Helper, for example. I tried to extract the essentials from my code. That's why you see only a only a single column, "Gender", in the table. Hopefully it is still syntactically correct:

@model IEnumerable<BusinessLayer.Employee>
<table>
    @foreach (var employee in Model) 
    {    
        <tr>
            <td>
            @{

                var listItems = new List<SelectListItem>()
                {
                    new SelectListItem {Text = "Male",   Value = "M"},
                    new SelectListItem {Text = "Female", Value = "F"}
                };

                @Html.DropDownListFor(m => employee.Gender, listItems, listItems.Find(i => i.Value == employee.Gender).Text)                          
            }  

            </td>
        </tr>
    }
</table>        

There are two Employees in the Model object, an IEnumerable of Employee and the following HTML is generated

<table> 
    <tr>
        <td>
            <select id="employee_Gender" name="employee.Gender"><option value="">Male</option>
                <option value="M">Male</option>
                <option value="F">Female</option>
            </select>
    </tr>       
        </td>    
             <select id="employee_Gender" name="employee.Gender"><option value="">Female</option>
                <option value="M">Male</option>
                <option value="F">Female</option>
             </select>                
        </td>
</table>                

Looking at the first param of the DropDownListFor Method,

@Html.DropDownListFor(m => employee.Gender, ...

...Do I understand correctly that the "m" represents the instance of the model class that was passed into the View? In the online examples that I have seen, I have seen examples where the "m" appears to refer to the model class but where the model is a single instance class, for example, a single Employee object, rather than a collection of Employees as is the case here where I want to display a table list of Employees. I'm assuming that the intent of the first param of the DropDownListFor Method is "point/bind' to a property in the model, so that's why I made m => employee.Gender. Is this what I should be doing when the model is a collection of Employees rather than a single Employee? If so, I am confused as to how I can generate unique IDs for the two drop down lists which were both assigned "employee_Gender" for both the NAME and ID attributes.

For the 3rd parameter of the Helper DropDownListFor,

listItems.Find(i => i.Value == employee.Gender).Text

Is this reasonable? The value for employee.Gender is either "M" or "F" but the display Text is "Male" and "Female." I am confused whether this param is used to specify a default "NO SELECT" first value or whether this param is used to select from the drop down the value of the current Employee---or perhaps it can do both? For example, does it select the Text specified if found and otherwise add the text specified as the FIRST? parameter if the value is not found? That appears to be how it works from what I see. Can this 3rd param be simplified or is my example reasonable?

Thanks for your patience in reading my many flurry of questions in trying to better understand this.

like image 682
Chad Avatar asked Nov 01 '13 03:11

Chad


People also ask

What is HTML DropDownListFor?

DropDownListFor() The Html. DropDownListFor<TModel,TProperty> extension method is a strongly typed extension method generates <select> element for the property specified using a lambda expression. Visit docs.microsoft.com to know all the overloads of DropDownListFor method.

What is the difference between DropDownList and DropDownListFor?

DropdownListFor is support strongly type and it name assign by lambda Expression so it shows compile time error if have any error. DropdownList not support this.


1 Answers

Part 1: Explaining Lambda magic

You're not alone. Lambdas + MVC make coding wicked easy, but they also make it seem rather magical (due to the abstraction).

Looking at the first param of the DropDownListFor Method [...] Do I understand correctly that the "m" represents the instance of the model class that was passed into the View?

Yes.

HTML Helpers + Lambdas in Razor are simple and magical because they are taking a shortcut and not actually revealing to you what's going on.

First, let's take a look at @Html. We know @ begins our Razor syntax and then Html is magic. Actually, Html is an HtmlHelper object that is automatically initialised and given to you. More specifically it's an HtmlHelper<TModel>. The Razor HTML editor is smart and knows ahead of time what type TModel will be based on what you've said this view's model type is. That's why you have so much intellisense.

When you type

@model IEnumerable<BusinessLayer.Employee>

The editor reads that and makes an assumption now that the HTML Helper will be HtmlHelper<IEnumerable<BusinessLayer.Employee>>. When it comes time to compile the page, the HTML helper will in fact be that type (of course).

So what about DropDownListFor or any other extension method?

Looking at DropDownListFor we can see that it's actually DropDownListFor<TModel, TProperty>. We now understand that TModel is our view's model type. DropDownListFor knows about this because the method is extending HtmlHelper<TModel>. Therefore DropDownListFor knows that the incoming type is whatever type is defined at the top of the view. What about TProperty?

TProperty is the return type. That's the type that you specify when you select your property. The view gives HtmlHelper the model type, who then gives DropDownListFor the model type and now that you're in a lambda expression: (x => x.Property) you select the property which then selects the type for you; in this case a string (Gender).

Part 2: Your problem

It's hard to answer your question without knowing exactly what you're trying to achieve. Do you have a collection of Employees and you want to display multiple gender dropdown boxes for each and then save them?

When dealing with collections it's a little more tricky, since MVC doesn't handle them well out of the box; it's usually best to write your own solutions according to what you need done.

I don't really like the idea of a single view getting a collection of things on a page. Consider this piece of logic:

Your way:

  • Get collection of Employees
  • Give Employees to a view
  • Have view create a single SelectListItem
  • Loop through and display the SelectList for each Employee

My way

  • Get collection of Employees
  • Give employees to a view
  • Have the view loop through and pass each Employee to another view (partial)
  • Each partial deals with a single Employee

With MVC do try to break things down into small, logical parts. Views should be stupid; meaning they shouldn't really do any logic or thinking. Things become easier this way and it makes sure that your views don't grow into monsters.

Example solution walk-through

Try this:

Create a new PartialView called _EmployeeGender.cshtml in the same folder as the view you're using.

Use this code

_EmployeeGender.cshtml

@model BusinessLayer.Employee

<tr>
    <td>
    @{

        var listItems = new List<SelectListItem>()
        {
            new SelectListItem {Text = "Male",   Value = "M"},
            new SelectListItem {Text = "Female", Value = "F"}
        };

        @Html.DropDownListFor(m => m.Gender, listItems, string.Empty)
    }  

    </td>
</tr>

Your original view

@model IEnumerable<BusinessLayer.Employee>
@{
    ViewBag.Title = "Employees";
}

<h2>Employees</h2>

<table>
    @foreach (var employee in Model) 
    {
        Html.RenderPartial("_EmployeeGender", employee);
    }
</table>

Results

Let's have a look at our generated HTML now:

<table>
<tr>
    <td>
<select id="Gender" name="Gender"><option value=""></option>
<option selected="selected" value="M">Male</option>
<option value="F">Female</option>
</select>  

    </td>
</tr><tr>
    <td>
<select id="Gender" name="Gender"><option value=""></option>
<option value="M">Male</option>
<option selected="selected" value="F">Female</option>
</select>  

    </td>
</tr></table>

We can see that there is now a blank selection and that our dropdown boxes are automatically selected with the Employee's values (I create one male and one female employee).

Do Note that the id and name HTML attributes are the same. If you want to submit a form with these values then it will require more work. But this is a reasonable starting point for you.

like image 135
Rowan Freeman Avatar answered Sep 30 '22 17:09

Rowan Freeman