3958 Views // 0 Comments // Not Rated

A Hackless Way To Get Long Labels In A Bootstrap Switch

When I first got down and dirty with Bootstrap, I was a little surprised that it didn't do much with checkboxes. I've never seen so much makeup and glitter adoring text inputs; checkboxes seemed to remain naked little squares. Then I found Bootstrap Switch and finally gave my checkboxes a chance to saunter down the catwalk along with their other dolled-up counterparts.

And then, as it always seems to go, after only about five minutes into using a third party plugin, I found myself trying to do something unsupported - in this case, that being use words in my switch longer than eight characters each. I'm not doing anything crazy; my labels are "Check In" and "Check Out." You can absolutely control this verbiage with the "data-on-text" and "data-off-text" attributes. But when added to my otherwise pristine Bootstrap UI, I couldn't live with the final "t" being cut off, and my requirements disallowed me from using slightly shorter synonyms.

So I wrapped my checkboxes in an HtmlHelper and added some JavaScript to automatically turn them into switches. Now, like a plastic surgeon, I could start sculpting. I knew this fix had to be as simple as making the control longer, so I started trying to insert widths all over the few nested divs the plugin renders. But nothing took. I then tried using some jQuery to update the width dynamically after calling bootstrapSwitch() on my checkbox, but that just stretched the control out.

So doing it too soon had no effect, and doing it too late screwed up the internal sizing calculations. In situations like this, CSS turns out to be the answer. By welding properties onto classes, we can manipulate third party controls without hacking them. Now of course, taking dependencies on the HTML structure of a component is a hack; hijacking their CSS is maybe sneaky at worst.

I proved my CSS theory by setting a hardcoded width on the class of the div container (bootstrap-switch-container) and finally seeing my switch take up enough real estate to display the full text of both options. But this won't do as a solution of course, since it breaks down with dynamic text and multiple controls. So how do we fix this without a hack?

Well, after spending the better part of a train ride inspecting the outputted HTML of my control, I noticed something very interesting that Bootstrap Switch does: it concatenates the name of the input to the "bootstrap-switch-id-" class of the outermost div! That's my hook! So I added a dynamic style tag to my helper just before the input that sets a width on this class. I also had to put the following in my CSS to force the now-accommodated-for labels to take advantage of their new homes:

Code Listing 1

  1. .bootstrap-switch-container span { white-space: nowrap; }

So, yes, the only drawback is that the developer has to supply a width that will work for the text of the two options. I'm sure you can do some sort of measurement of the two spans and resize things on-the-fly, but that's really outside the scope of what we're trying to accomplish. If you have to dig that deeply, then perhaps the component isn't the right choice. Besides, remember that this is just a checkbox; a hardcoded width isn't the end of the world...just the end of this post. Below is the helper method. Have fun long switching!

Code Listing 2

  1. public static MvcHtmlString SwitchCheckbox<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, string onText = "On", string offText = "Off", string width = null, string color = "primary")
  2. {
  3. //initialization
  4. StringBuilder sb = new StringBuilder();
  5. ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
  6. string name = metadata.PropertyName;
  7. //switch css
  8. if (!string.IsNullOrWhiteSpace(width))
  9. sb.AppendFormat("<style type=\"text/css\">.bootstrap-switch-id-{0} {{ width: {1}px; }}</style>", name, width.TrimEnd("px%".ToCharArray()));
  10. //build tag
  11. sb.Append(LabelExtensions.LabelFor(htmlHelper, expression).ToString());
  12. sb.Append("<br />");
  13. sb.Append(htmlHelper.CheckBoxFor(expression, new { data_on_color = color, data_on_text = onText, data_off_text = offText }).ToString());
  14. //switch
  15. sb.AppendFormat("<script type=\"text/javascript\">$(function() {{ {0} }});</script>", string.Format("$('#{0}').bootstrapSwitch();", name));
  16. //return
  17. return MvcHtmlString.Create(sb.ToString());
  18. }

One thing I want to point out from the above listing is the property names of the anonymous type on Line #13. We've all had to use the "@class" attribute when setting CSS in our Html Helpers, but .NET classes can't have dashes, so how do we set all our "data-" properties? Well since its third version, MVC has been converting these underscores to dashes, since underscores aren't valid characters in HTML attribute names. Adorably convenient!

No Tags

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.