Используйте Html.RadioButtonFor и Html.LabelFor для той же модели, но разные значения
У меня есть этот шаблон 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 и обратиться к этому с помощью моего ярлыка, но это не очень хорошо, не так ли? Особенно потому, что я в цикле и не могу просто использовать имя "значение" с добавленным номером, которое также будет в конечном итоге в нескольких идентификаторах в моей окончательной разметке HTML.
Не должно быть хорошего решения для этого?
Ответы
Ответ 1
Мне было интересно, как MVC определяет "вложенные" имена полей и идентификаторы. Потребовалось немного исследований исходного кода MVC, чтобы понять, но я думаю, что у меня есть хорошее решение для вас.
Как EditorTemplates и DisplayTemplates определяют имена полей и идентификаторы
С введением EditorTemplates и DisplayTemplates в среду MVC добавлена ViewData.TemplateInfo
, которая содержит, помимо прочего, текущий "префикс поля", такой как "Items[1]."
. Вложенные шаблоны используют это для создания уникальных имен и идентификаторов.
Создайте наши собственные уникальные идентификаторы:
Класс TemplateInfo
содержит интересный метод, GetFullHtmlFieldId
. Мы можем использовать это для создания наших собственных уникальных идентификаторов, например:
@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("fieldName");}
@* This will result in something like "Items_1__fieldName" *@
Для Win
Здесь, как добиться правильного поведения для вашего примера:
<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>
Отказ
Синтаксис My Razor недостаточно развит, поэтому, пожалуйста, дайте мне знать, есть ли у этого кода синтаксические ошибки.
Для чего стоит
Очень печально, что эта функциональность не встроена в RadioButtonFor
. Кажется логичным, что все отображаемые кнопки радио должны иметь идентификатор, который является комбинацией его name
AND value
, но это не так - возможно, потому, что это будет отличаться от всех других хелм-хелперов.
Создание собственных методов расширения для этой функциональности также кажется логичным выбором. Тем не менее, это может оказаться сложным с использованием синтаксиса выражения... поэтому я рекомендую перегружать .RadioButton(name, value, ...)
вместо RadioButtonFor(expression, ...)
. И вам может понадобиться перегрузка для .Label(name, value)
.
Я надеюсь, что все имело смысл, потому что в этом пункте много "заполнить пробелы".
Ответ 2
Не переустраивайте решение для этого. Все, что вы пытаетесь сделать, это заставить переключатели реагировать на щелчки на тексте. Держите его простым и просто оберните свои переключатели ярлыками меток:
<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 в вашей модели просмотра (например, "[Display (Name =" Enter your Name ")]).
С помощью переключателей имя не особенно полезно, потому что у вас есть другая строка текста для каждого переключателя, что означает, что вы все равно зацикливали текст на свой взгляд.
Ответ 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 })
это позволяет вам щелкнуть по метке и выбрать соответствующую радиокамеру, как вы ожидали.
Ответ 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());
}
Ответ 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>