Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Html.RadioButtonFor and Html.LabelFor for the same Model but different values

I have this Razor Template

<table> <tr>     <td>@Html.RadioButtonFor(i => i.Value, "1")</td>     <td>@Html.LabelFor(i => i.Value, "true")</td> </tr> <tr>     <td>@Html.RadioButtonFor(i => i.Value, "0")</td>     <td>@Html.LabelFor(i => i.Value, "false")</td> </tr> </table> 

That gives me this HTML

<table> <tr>     <td><input id="Items_1__Value" name="Items[1].Value" type="radio" value="1" /></td>     <td><label for="Items_1__Value">true</label></td> </tr> <tr>     <td><input checked="checked" id="Items_1__Value" name="Items[1].Value" type="radio" value="0" /></td>     <td><label for="Items_1__Value">false</label></td> </tr> </table> 

So I have the ID Items_1__Value twice which is - of course - not good and does not work in a browser when I click on the second label "false" the first radio will be activated.

I know I could add an own Id at RadioButtonFor and refer to that with my label, but that's not pretty good, is it? Especially because I'm in a loop and cannot just use the name "value" with an added number, that would be end up in multiple Dom Ids in my final HTML markup as well.

Shouldn't be a good solution for this?

like image 436
Marc Avatar asked Nov 30 '11 01:11

Marc


2 Answers

Don't over-engineer a solution for this. All you are trying to accomplish is to have the radio buttons respond to clicks on the text. Keep it simple and just wrap your radio buttons in label tags:

<table> <tr>     <td><label>@Html.RadioButtonFor(i => i.Value, "1")True</label></td> </tr> <tr>     <td><label>@Html.RadioButtonFor(i => i.Value, "0")False</label></td> </tr> </table> 

The LabelFor html helper is usually used to bring in the Name from the Display attribute on your View Model (e.g. "[Display(Name = "Enter your Name")]).

With radio buttons, the name isn't particularly useful, because you have a different line of text for each radio button, meaning you are stuck hard coding the text into your view anyway.

like image 191
Roger Rouse Avatar answered Sep 28 '22 02:09

Roger Rouse


I've been wondering how MVC determines "nested" field names and IDs. It took a bit of research into the MVC source code to figure out, but I think I have a good solution for you.

How EditorTemplates and DisplayTemplates determine field names and IDs

With the introduction of EditorTemplates and DisplayTemplates, the MVC framework added ViewData.TemplateInfo that contains, among other things, the current "field prefix", such as "Items[1].". Nested templates use this to create unique names and IDs.

Create our own unique IDs:

The TemplateInfo class contains an interesting method, GetFullHtmlFieldId. We can use this to create our own unique IDs like so:

@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("fieldName");} @* This will result in something like "Items_1__fieldName" *@ 

For The Win

Here's how to achieve the correct behavior for your example:

<table> <tr>     @{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioTrue");}     <td>@Html.RadioButtonFor(i => i.Value, "1", new{id})</td>     <td>@Html.LabelFor(i => i.Value, "true", new{@for=id})</td> </tr> <tr>     @{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioFalse");}     <td>@Html.RadioButtonFor(i => i.Value, "0", new{id})</td>     <td>@Html.LabelFor(i => i.Value, "false", new{@for=id})</td> </tr> </table> 

Which will give you the following HTML:

<table> <tr>     <td><input id="Items_1__radioTrue" name="Items[1].Value" type="radio" value="1" /></td>     <td><label for="Items_1__radioTrue">true</label></td> </tr> <tr>     <td><input checked="checked" id="Items_1__radioFalse" name="Items[1].Value" type="radio" value="0" /></td>     <td><label for="Items_1__radioFalse">false</label></td> </tr> </table> 

Disclaimer

My Razor syntax is underdeveloped, so please let me know if this code has syntax errors.

For what its worth

It's pretty unfortunate that this functionality isn't built-in to RadioButtonFor. It seems logical that all rendered Radio Buttons should have an ID that is a combination of its name AND value, but that's not the case -- maybe because that would be different from all other Html helpers.
Creating your own extension methods for this functionality seems like a logical choice, too. However, it might get tricky using the "expression syntax" ... so I'd recommend overloading .RadioButton(name, value, ...) instead of RadioButtonFor(expression, ...). And you might want an overload for .Label(name, value) too.
I hope that all made sense, because there's a lot of "fill in the blanks" in that paragraph.

like image 31
Scott Rippey Avatar answered Sep 28 '22 00:09

Scott Rippey