Пользовательский помощник для создания HTML-тегов для переключателя и соответствующей метки

Я искал решение о переключателях и соответствующих ярлыках. Мне нравится, как мы можем выбрать каждую радио-кнопку, нажав на ярлык, связанный. По умолчанию это работает не очень хорошо. Я имею в виду, что ярлыки неправильно связаны с переключателями.

Пример: допустим, у нас есть свойство с именем Revoked с возможными значениями Да / Нет. Мы хотели бы использовать переключатели, чтобы позволить пользователю выбрать значение.

Проблема: когда HTML-теги генерируются из MVC (Html.LabelFor, Html.RadioButtonFor), идентификаторы обеих радиокнопок (Да / Нет) совпадают. Таким образом, невозможно связать каждую метку с соответствующей радиокнопкой.

Решение: я создал свой собственный помощник для генерации HTML-тегов с правильным и уникальным идентификатором.

Вот мой помощник:

    public static MvcHtmlString RadioButtonWithLabelFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object value, object labelText)
    {
        object currentValue = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model;
        string property = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).PropertyName;

        // Build the radio button html tag
        TagBuilder htmlRadio = new TagBuilder("input");
        htmlRadio.MergeAttribute("type", "radio");
        htmlRadio.MergeAttribute("id", property + value);
        htmlRadio.MergeAttribute("name", property);
        htmlRadio.MergeAttribute("value", (string)value);

        if (currentValue != null && value.ToString() == currentValue.ToString()) htmlRadio.MergeAttribute("checked", "checked");

        // Build the label html tag
        TagBuilder htmlLabel = new TagBuilder("label");
        htmlLabel.MergeAttribute("for", property + value);
        htmlLabel.SetInnerText((string)labelText);

        // Return the concatenation of both tags
        return MvcHtmlString.Create(htmlRadio.ToString(TagRenderMode.SelfClosing) + htmlLabel.ToString());
    }

Это работает, но мне нужно посоветовать. Как вы думаете? Это эффективно? Я все еще новичок в мире ASP.NET MVC, поэтому любая помощь очень ценится.

Благодарю.

1 ответ

Решение

Помимо некоторых незначительных улучшений, которые могут быть сделаны, помощник выглядит хорошо:

  • Вам не нужно звонить ModelMetadata.FromLambdaExpression дважды с одинаковыми аргументами
  • Для создания идентификатора вы объединяете имя свойства со значением, но это значение может содержать любые символы, в то время как идентификатор в HTML допускает только определенные символы. Вы должны продезинфицировать это.
  • Вы преобразуете значение и currentValue в строки, которые могут завершиться с ошибкой, если помощник используется в каком-либо другом типе свойства. В этом случае либо заставьте помощника работать только со строковыми свойствами, отражая подпись помощника, либо используйте Convert.ToString(),

Вот переработанная версия, которая учитывает эти замечания:

public static IHtmlString RadioButtonWithLabelFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper, 
    Expression<Func<TModel, TProperty>> expression, 
    TProperty value, 
    string labelText
)
{
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    object currentValue = metadata.Model;
    string property = metadata.PropertyName;

    // Build the radio button html tag
    var htmlRadio = new TagBuilder("input");
    htmlRadio.GenerateId(property + value);
    htmlRadio.Attributes["type"] = "radio";
    htmlRadio.Attributes["name"] = property;
    htmlRadio.Attributes["value"] = Convert.ToString(value);

    if (object.Equals(currentValue, value))
    {
        htmlRadio.Attributes["checked"] = "checked";
    }

    // Build the label html tag
    var label = new TagBuilder("label");
    label.Attributes["for"] = htmlRadio.Attributes["id"];
    label.SetInnerText(labelText);

    // Return the concatenation of both tags
    return new HtmlString(
        htmlRadio.ToString(TagRenderMode.SelfClosing) + label.ToString()
    );
}
Другие вопросы по тегам