使用Html.RadioButtonFor和Html.LabelFor获取相同的Model但不同的值

时间:2011-11-30 01:45:44

标签: asp.net-mvc-3 razor

我有这个剃刀模板

<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>

这给了我这个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>

所以我有两次ID Items_1__Value - 当然 - 不好,当我点击第二个标签“false”时,浏览器不能正常工作,第一个收音机将被激活。

我知道我可以在RadioButtonFor中添加一个自己的ID并用我的标签来引用它,但这不是很好,是吗?特别是因为我处于一个循环中而且不能只使用带有附加数字的名称“value”,这也会在我的最终HTML标记中以多个Dom Ids结束。

不应该是良好的解决方案吗?

7 个答案:

答案 0 :(得分:57)

不要过度设计解决方案。你要做的就是让单选按钮响应文本的点击。保持简单,只需将单选按钮包裹在标签标签中:

<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>

LabelFor html帮助程序通常用于从View模型的Display属性中引入Name(例如“[Display(Name =”输入您的名字))]。

使用单选按钮时,名称并不是特别有用,因为每个单选按钮都有不同的文本行,这意味着您无论如何都难以将文本编码到视图中。

答案 1 :(得分:47)

我一直想知道MVC如何确定“嵌套”字段名称和ID。对MVC源代码进行了一些研究,但我觉得我有一个很好的解决方案。

EditorTemplates和DisplayTemplates如何确定字段名称和ID

随着EditorTemplates和DisplayTemplates的引入,MVC框架添加了ViewData.TemplateInfo,其中包含当前“字段前缀”,例如"Items[1]."。嵌套模板使用它来创建唯一的名称和ID。

创建我们自己的唯一ID:

TemplateInfo类包含一个有趣的方法GetFullHtmlFieldId。我们可以使用它来创建我们自己的唯一ID,如下所示:

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

胜利

以下是如何为您的示例实现正确的行为:

<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>

这将为您提供以下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>

声明

我的Razor语法不发达,所以如果此代码有语法错误,请告诉我。

它的价值

非常不幸的是,RadioButtonFor没有内置此功能。似乎合乎逻辑的是,所有渲染的单选按钮都应该具有一个ID namevalue的组合,但事实并非如此 - 可能因为它与所有其他Html助手不同。登记/> 为此功能创建自己的扩展方法似乎也是一种合理的选择。但是,使用“表达式语法”可能会变得棘手...所以我建议重载.RadioButton(name, value, ...)而不是RadioButtonFor(expression, ...)。你可能也希望.Label(name, value)过载 我希望这一切都有道理,因为该段落中有很多“填空”。

答案 2 :(得分:8)

@Scott Rippey几乎拥有它,但我猜他必须使用不同版本的MVC3给我,因为对我来说@Html.LabelFor没有重载需要3个参数。我发现使用普通@Html.Label可以正常工作:

@{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 })

这允许您单击标签并按照您的预期选择相关的单选按钮。

答案 3 :(得分:1)

不完美但是工作,

<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++ +"_"));
    }
}

答案 4 :(得分:0)

这是您可以使用的HtmlHelper,但您可以自定义它。只有勉强测试,所以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());
    }

答案 5 :(得分:0)

您可以添加带标签的文字

<td>@Html.RadioButtonFor(i => i.Value, true) <text>True</text></td>
<td>@Html.RadioButtonFor(i => i.Value, false) <text>False</text></td>

答案 6 :(得分:-2)

显然有一个很好的解决方案

    <td>@Html.RadioButtonFor(i => i.Value, true)</td>
    <td>@Html.RadioButtonFor(i => i.Value, false)</td>