将 Html.RadioButtonFor 和 Html.LabelFor 用于相同的模型但不同的值
Posted
技术标签:
【中文标题】将 Html.RadioButtonFor 和 Html.LabelFor 用于相同的模型但不同的值【英文标题】:Use Html.RadioButtonFor and Html.LabelFor for the same Model but different values 【发布时间】:2012-01-09 08:21:25 【问题描述】:我有这个 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 并用我的标签引用它,但这不是很好,是吗?特别是因为我处于一个循环中并且不能只使用名称“值”和一个附加数字,这最终也会在我的最终 HTML 标记中出现多个 Dom Id。
不应该是一个好的解决方案吗?
【问题讨论】:
我认为你最好的选择是创建你自己的自定义 HtmlHelper,它可以输出一个单选按钮和一个标签,考虑到你传入的默认值。 我选择了简单的选项并使用 Html.Raw 来编写标签 html,它只需要做这么多。使用ViewData.TemplateInfo.GetFullHtmlFieldId
生成单选按钮的 id,以便在标签中使用。
【参考方案1】:
不要为此过度设计解决方案。您想要完成的只是让单选按钮响应对文本的点击。保持简单,只需将单选按钮包装在标签标签中:
<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 帮助器通常用于从视图模型的 Display 属性中引入 Name(例如“[Display(Name = "Enter your Name")])。
对于单选按钮,名称并不是特别有用,因为每个单选按钮都有不同的文本行,这意味着无论如何您都无法将文本硬编码到视图中。
【讨论】:
+1 你一针见血:“不要为此过度设计解决方案。” 让我开心:“不要过度设计”! 一般来说,不要过度设计是很好的建议。如果可以的话,我会给你不止一票。 对于那些想知道这是否是 HTML 中的好习惯并且没有任何其他副作用的人,请参阅***.com/questions/774054/… 这是个好主意,但我认为在这种情况下您不能为:selected
之类的选择器设置标签样式?【参考方案2】:
我一直想知道 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", newid)</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", newid)</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 是其name
和 value
的组合,这似乎是合乎逻辑的,但事实并非如此——可能是因为这与所有其他 Html 帮助程序不同。
为此功能创建自己的扩展方法似乎也是一个合乎逻辑的选择。但是,使用“表达式语法”可能会变得棘手......所以我建议重载.RadioButton(name, value, ...)
而不是RadioButtonFor(expression, ...)
。您可能还希望 .Label(name, value)
重载。
我希望这一切都说得通,因为那段中有很多“填空”。
【讨论】:
编译器可能会抱怨上面代码new for = id
中声明了匿名类型。这是因为for
是保留关键字。在这种情况下,只需大写属性名称,如new For = id
。谢谢斯科特。
我没有注意到。我通常使用new @for = id, @class = "cssClass"
之类的语法,但我从未想过使用大写属性。你确认输出是小写的吗?
是的,生成的属性的名称是小写的,但是我已经切换到@for
语法,因为它似乎是惯例。干杯
您可以改用字典重载:new Dictionary<string, object>() "for", id, "class", "cssClass"
@ScottRippey 怎么可能只使用new id
?引擎如何知道将该值映射到标签的id
属性?【参考方案3】:
@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 )
这允许您单击标签并按预期选择相关的单选按钮。
【讨论】:
老实说,我没有测试我的代码。但是,我确实看过the documentation forHtml.LabelFor(expression, labelText, htmlAttributes)
,看起来应该可以正常工作。
@ScottRippey 那是针对 MVC4 的,因为问题是关于 MVC3,所以这应该是公认的答案。
赞成,这让我走上了正确的道路,可以解决我在点击标签时没有激活 IE6 中的单选按钮的问题。上述答案中未包含的是 id 和 for 属性。【参考方案4】:
虽然不完美,但可以工作,
<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++ +"_"));
【讨论】:
【参考方案5】:这是一个您可以使用的 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());
【讨论】:
我把它分成 2 个助手,一个用于标签,一个用于单选按钮。此外,我正在更改标签以解决内部 HTML 需要与值不同的情况,例如,如果值是 2 个单词。【参考方案6】:您可以添加带有标签的文本
<td>@Html.RadioButtonFor(i => i.Value, true) <text>True</text></td>
<td>@Html.RadioButtonFor(i => i.Value, false) <text>False</text></td>
【讨论】:
【参考方案7】:显然有一个很好的解决方案
<td>@Html.RadioButtonFor(i => i.Value, true)</td>
<td>@Html.RadioButtonFor(i => i.Value, false)</td>
【讨论】:
对不起,但这不是一个好的解决方案——使用该代码,我将只得到单选按钮,但没有标签。我想要有标签,用户可以单击以激活单选按钮。只是收音机对用户不友好。 是的,我有点误读了你的问题。查看答案here,它使用比 bool 更复杂的值,这将允许有工作标签 我不明白 - 这对我的情况有何帮助?在另一个答案中使用了不同的属性,我只有一个具有两个不同值的属性。您能否按照您认为适合我的方式更新您的答案? 不不,你是对的 - 我在考虑我自己的代码,我有一个特殊的编辑器,用于为枚举创建 id,发布时我没有意识到它不是自动的。见here以上是关于将 Html.RadioButtonFor 和 Html.LabelFor 用于相同的模型但不同的值的主要内容,如果未能解决你的问题,请参考以下文章
Html.RadioButtonFor 单选按钮不在 Safari 或 Chrome 中呈现
Razor- 为 radioButtonFor 赋予“属性”
工作总结 @Html 辅助方法 为 生成的 标签设置元素属性 htmlAttributes 一个对象,其中包含要为该元素设置的 HTML 特性。