14

So I'm using Twitter Bootstrap and most of my forms are looking fantastic with this

       <div class="control-group">
            @Html.LabelFor(m => m.Prop)
            <div class="controls">
                @Html.EditorFor(m => m.Prop)
            </div>
            @Html.ValidationMessageFor(model => model.Prop)
        </div>

The only issue is with Radio Buttons and Check Boxes. Twitter Bootstrap calls for HTML5 style labels that include the radio or checkbox input INSIDE the label tag like this

        <label class="checkbox">
           <input type="checkbox"> Check me out
        </label>

If I can't create these with a with @Html or and overload can I at least get to the text that's created by Labelfor?

        <label class="checkbox">
           @Html.EditorFor(m=> m.Prop)
           @Html.TheVariableThatContainsTheTextThatLabelForUsesFor(m => m.Prop)
        </label>
1

5 Answers 5

15

Why can't you create these with an @Html. If you write your own extension method (see below) that should do it, no?


public static class HtmlHelperExtensions
    {
        public static MvcHtmlString MyCheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, object htmlLabelAttributes = null, object htmlCheckBoxAttributes = null)
        {
            var checkbox = htmlHelper.CheckBoxFor(expression, htmlCheckBoxAttributes);

            var labelTag = new TagBuilder("label");
            labelTag.AddCssClass("checkbox");
            labelTag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlLabelAttributes));
            labelTag.InnerHtml = checkbox.ToString();

            return new MvcHtmlString(labelTag.ToString());
        }
    }

EDIT:

How about this revised version. This replicates exactly what the label does.


public static class HtmlHelperExtensions
{
    public static MvcHtmlString MyCheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, object htmlLabelAttributes = null, object htmlCheckBoxAttributes = null)
    {
        var checkbox = htmlHelper.CheckBoxFor(expression, htmlCheckBoxAttributes);

        var labelTag = new TagBuilder("label");
        var checkboxName = ExpressionHelper.GetExpressionText(expression);
        labelTag.AddCssClass("checkbox");
        labelTag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlLabelAttributes));
        labelTag.InnerHtml = checkbox.ToString() + LabelHelper(ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData), checkboxName);

        return new MvcHtmlString(labelTag.ToString());
    }

    private static MvcHtmlString LabelHelper(ModelMetadata metadata, string fieldName)
    {
        string labelText;
        var displayName = metadata.DisplayName;

        if (displayName == null)
        {
            var propertyName = metadata.PropertyName;

            labelText = propertyName ?? fieldName.Split(new[] { '.' }).Last();
        }
        else
        {
            labelText = displayName;
        }

        if (string.IsNullOrEmpty(labelText))
        {
            return MvcHtmlString.Empty;
        }

        return new MvcHtmlString(labelText);
    }
}

I should note that with MVC 4 there is a DisplayNameFor Helper, so that whole label business could be simplified a bit.

Sign up to request clarification or add additional context in comments.

1 Comment

Thats really close but it's missing the contents of LabelFor, so the textbox is displayed with no text. So I guess I need to add someting like var label = htmlHelper.LabelFor(expression, htmlCheckBoxAttributes);
11

Touching on what Mirko mentioned about MVC 4, this is the code i'm using in the view (no custom helper).

<div class="checkbox">
    <label>
        @Html.CheckBoxFor(m => m.RememberMe) @Html.DisplayNameFor(m => m.RememberMe)
    </label>
</div>

1 Comment

Short and simple. Perfect for what I needed. I prefer this because the custom helper seems like overkill
5

I just built a solution that mirrors the way forms work in ASP.NET MVC.

@using (Html.BeginLabelFor(m => m.CheckMe, new { @class = "checkbox" })) {
    @Html.CheckBoxFor(m => m.CheckMe)
}

This renders the nested structure, while allowing you to use the normal HTML helpers for checkboxes and radio buttons.

<label class="checkbox" for="CheckMe">
    <input type="checkbox" name="CheckMe" value="true" /> Hey, Check Me!
</label>

The BeginLabel and BeginLabelFor support the same signatures as Label and LabelFor, respectively.

https://github.com/toddlucas/bootstrap-mvc.net

I hope someone else finds this useful.

Edit:

Another alternative, which is employed in the new Visual Studio 2013 MVC templates, is to do the following:

<div class="checkbox">
    @Html.CheckBoxFor(m => m.CheckMe)
    @Html.LabelFor(m => m.CheckMe)
</div>

The new templates use Twitter Bootstrap 3.0, which follows the same convention as 2.x.

1 Comment

And if you need special display text for the label, either configure it as a Display attribute in your model code or use the alternate form of the LabelFor method that specifies the label text to use.
2

My final solution is an Custom Bootstrap Label helper

    public static MvcHtmlString BootstrapCheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, object htmlLabelAttributes = null, object htmlCheckBoxAttributes = null)
    {
        var checkbox = htmlHelper.CheckBoxFor(expression, htmlCheckBoxAttributes);
        var label = htmlHelper.LabelFor(expression, htmlCheckBoxAttributes);
        string text = Regex.Match(label.ToString(), "(?<=^|>)[^><]+?(?=<|$)").Value;

        var labelTag = new TagBuilder("label");
        labelTag.AddCssClass("checkbox");
        labelTag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlLabelAttributes));
        labelTag.InnerHtml = checkbox.ToString() + text;

        return new MvcHtmlString(labelTag.ToString());
    }

1 Comment

I added a revised version. Take a look, the LabelHelper logic is exactly what the framework does internally to come up with the label text, no need to &quotScreen Scrape&quot; it. Hope it helps.
2

Instead of rendering the return value of the LabelFor method directly like this:

@Html.LabelFor(m => m.Prop, "Text <a>HTML Tag</a>")

First set the output to a variable decode that and the render that decoded text:

MvcHtmlString label = Html.LabelFor(m => m.Prop, "Text <a>HTML Tag</a>");
@Html.Raw(HttpUtility.HtmlDecode(label.ToString()))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.