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

前端 未结 7 1822
陌清茗
陌清茗 2020-12-13 02:11

I have this Razor Template

@Html.RadioButtonFor(i => i.Value, \"1\") @Html.LabelFor(i =>
相关标签:
7条回答
  • 2020-12-13 02:43

    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.

    0 讨论(0)
  • 2020-12-13 02:48

    Apparently there is a good solution

        <td>@Html.RadioButtonFor(i => i.Value, true)</td>
        <td>@Html.RadioButtonFor(i => i.Value, false)</td>
    
    0 讨论(0)
  • 2020-12-13 02:50

    You can add text with tags

    <td>@Html.RadioButtonFor(i => i.Value, true) <text>True</text></td>
    <td>@Html.RadioButtonFor(i => i.Value, false) <text>False</text></td>
    
    0 讨论(0)
  • 2020-12-13 02:53

    Not Perfect but work though,

    <table>
    <tr>
        <td>@ReplaceName(Html.RadioButtonFor(i => i.Value, "1"))</td>
        <td>@Html.LabelFor(i => i.Value[0], "true")</td>
    </tr>
    <tr>
        <td>@ReplaceName(Html.RadioButtonFor(i => i.Value, "0"))</td>
        <td>@Html.LabelFor(i => i.Value[1], "false")</td>
    </tr>
    </table>
    
    
    @functions {
        int counter = 0;
        MvcHtmlString ReplaceName(MvcHtmlString html){
            return MvcHtmlString.Create(html.ToString().Replace("__Value", "__Value_" + counter++ +"_"));
        }
    }
    
    0 讨论(0)
  • 2020-12-13 02:57

    Here's an HtmlHelper you can use, though you may with to customize it. Only barely tested, so YMMV.

         public static MvcHtmlString RadioButtonWithLabelFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object value, object htmlAttributes = null)
         {
            var name = ExpressionHelper.GetExpressionText(expression);
            var id = helper.ViewData.TemplateInfo.GetFullHtmlFieldId(name + "_" + value);
    
            var viewData = new ViewDataDictionary(helper.ViewData) {{"id", id}};
    
            if (htmlAttributes != null)
            {
                var viewDataDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
                foreach (var keyValuePair in viewDataDictionary)
                {
                    viewData[keyValuePair.Key] = keyValuePair.Value;
                }
            }
    
            var radioButton = helper.RadioButtonFor(expression, value, viewData);
    
            var tagBuilder = new TagBuilder("label");
            tagBuilder.MergeAttribute("for", id);
            tagBuilder.InnerHtml = value.ToString();
    
            return new MvcHtmlString(radioButton.ToHtmlString() + tagBuilder.ToString());
        }
    
    0 讨论(0)
  • 2020-12-13 02:59

    @Scott Rippey nearly has it, but i guess he must be using a different version of MVC3 to me because for me @Html.LabelFor has no overloads that will take 3 arguments. I found that using the normal @Html.Label works just fine:

    @{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioButton_True");}
    @Html.Label(id, "True:")
    @Html.RadioButtonFor(m => m.radioButton, true, new { id })
    
    @{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioButton_False");}
    @Html.Label(id, "False:")
    @Html.RadioButtonFor(m => m.radioButton, false, new { id })
    

    this allows you to click on the label and select the associated radiobutton as you'd expect.

    0 讨论(0)
提交回复
热议问题