Custom helper for generating html tags for radio button and associated label

I was searching for a solution about radio buttons and associated labels. I like the way we can select each radio button by clicking on the label associated. By default, this doesn’t work very well. I mean the labels are not correctly associated with radio buttons.

Example: let’s say we have a property named Revoked with possible values Yes/No. We would like to use radio buttons to let the user choose the value.

The problem: when html tags are generated from MVC (Html.LabelFor, Html.RadioButtonFor), the ID of both radio buttons (Yes/No) are the same. Thus it is impossible to associate each label with the corresponding radio button.

The solution: I created my own custom helper for generating html tags with correct and unique ID.

Here is my helper:

    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());
    }

It works but I need advise. What do you think? Is it efficient? I’m still new to the world of ASP.NET MVC so any help is greatly appreciated.

Thanks.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Other than some minor improvements that could be made the helper looks fine:

  • You don’t need to call ModelMetadata.FromLambdaExpression twice with the same arguments
  • In order to generate the id you are concatenating the property name with the value but this value could contain any characters while an id in HTML allows only certain characters. You need to sanitize it.
  • You are casting both the value and currentValue to strings which might fail if the helper is used on some other property type. In this case either make the helper work only with string properties by reflecting on the helper signature or use Convert.ToString().

Here’s the refactored version which takes into account those remarks:

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()
    );
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x