17

When using an ASP.NET CheckBox (and in out case, inherited from a CheckBox) it renders a span around the checkbox input control, this span control is affecting jQuery scripts.

Is it possible to remove this span when rendering?

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
Mark Redman
  • 24,079
  • 20
  • 92
  • 147

15 Answers15

36

Found this useful tip:

In Code Behind, use InputAttributes instead of Attributes.

For Example, type this:

chk.InputAttributes.Add("onchange", "updateFields()")

instead of this:

chk.Attributes.Add("onchange", "updateFields()")

or instead of inline declarations:

<asp:CheckBox ID="chk" runat="server" onchange="updateFields()" />

The last two will cause the wrapping span.

j0k
  • 22,600
  • 28
  • 79
  • 90
Jon
  • 376
  • 3
  • 2
10

I just tried this on a test page and I'm not getting the around my CheckBox controls... are you sure it's the CheckBox that's rendering this? Is it conditional?

UPDATE: OK, it appears to be conditional on whether or not the CheckBox has extra attributes, including a CssClass setting... or a "disabled" attribute.

Bryan
  • 8,748
  • 7
  • 41
  • 62
  • Yes, it appears that all styles are added to a span wrapping the checkbox input control. I can seem to get rid of the span if I inherit from Control rather than checkbox, although I have to re-implement pretty much every property, eg an OnClientClick property that renders as onclick. I am using additional (non .net or custom attributes which as you mention may also be the cause) I would think that the ability to inherit from an asp.net CheckBox and elimiate the span would be easy, but its appears not. – Mark Redman Feb 02 '10 at 07:54
  • I would take Nick's suggestion then and override the Render method. You could take a shortcut by using the original CheckBox render method (cut and paste from Reflector) and just pull out the span tags. – Bryan Feb 02 '10 at 20:33
  • thanks for this, even occurs if CssClass is set to an empty string. – Andrew Afternoon-Delight Hayde Jul 17 '15 at 13:32
9

I don't know if this will work on this particular example. But if you make your own WebControl and you never want it to render spans around itself you can override the Controls render method like this:

public class MyWebControl : WebControl
{

  /* Your code 
             between here */

  protected override void Render(HtmlTextWriter writer)
  {
    RenderContents (writer);
  }
}

I guess that you could add the same to an inherited CheckBox... something like this:

public class MyCheckBox : CheckBox 
{

  /* Your code 
             between here */

  protected override void Render(HtmlTextWriter writer)
  {
    RenderContents (writer);
  }
}

The basic problem with the solution is better explained here:
http://www.marten-online.com/net/stripping-span-tag-from-webcontrol.html

mattsson
  • 1,132
  • 12
  • 18
4

I spent the last 3 hours pulling my hair to find a solution at this problem.

Here is what came out:

using System.Web.UI;
using System.Web.UI.WebControls;

/// <summary>
/// Represents a custom checkbox web control.
/// Prevents itself to be wrapped into a <span> tag when disabled.
/// </summary>
public class CustomCheckBox : CheckBox
{
    /// <summary>
    /// Renders the control to the specified HTML writer.
    /// </summary>
    /// <param name="writer">The HtmlTextWriter object that receives the control content.</param>
    protected override void Render(HtmlTextWriter writer)
    {
        // Use custom writer
        writer = new HtmlTextWriterNoSpan(writer);

        // Call base class
        base.Render(writer);
    }
}

Along with the custom control, you'll need a custom HtmlTextWriter:

using System.IO;
using System.Web.UI;

/// <summary>
/// Represents a custom HtmlTextWriter that displays no span tag.
/// </summary>
public class HtmlTextWriterNoSpan : HtmlTextWriter
{
    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="textWriter">Text writer.</param>
    public HtmlTextWriterNoSpan(TextWriter textWriter)
        : base(textWriter)
    { }

    /// <summary>
    /// Determines whether the specified markup element will be rendered to the requesting page.
    /// </summary>
    /// <param name="name">Name.</param>
    /// <param name="key">Tag key.</param>
    /// <returns>True if the markup element should be rendered, false otherwise.</returns>
    protected override bool OnTagRender(string name, HtmlTextWriterTag key)
    {
        // Do not render <span> tags
        if (key == HtmlTextWriterTag.Span)
            return false;

        // Otherwise, call the base class (always true)
        return base.OnTagRender(name, key);
    }
}

Just FYI, using:

checkbox.InputAttributes.Add("disabled", "disabled");

has the same effect but:

  1. It's not as convenient as checkbox.Enalbed = false;
  2. The attribute is removed after a postback when the checkbox is in a ListView.
Pedro
  • 3,511
  • 2
  • 26
  • 31
  • This successfully gets rid of the span, but now you can't add a css class to the checkbox. Good thought though! – EJC Sep 18 '17 at 16:49
3

Using Jquery

<script>
        $(".selector input").unwrap().addClass("cssclass");
</script>
Sushmit Patil
  • 1,335
  • 1
  • 14
  • 26
2
    protected override HtmlTextWriterTag TagKey
    {
        get
        {              
            return HtmlTextWriterTag.Div;
        }
    }

should do

1

I've found that by implementing a constructor like the one below, you can specify the container tag for your control.

public MyCustomControl() : base(HtmlTextWriterTag.Div)
{
}

You can replace the HtmlTextWriterTag with any of the aviable options, such as Div in the example above. The default is Span.

Andres A.
  • 1,329
  • 2
  • 21
  • 37
1

You can use the input/checkbox control directly if you don't need a label, or can put one yourself:

<input type="checkbox" id="CheckBox1" runat="server" />
<label for="CheckBox1">My Label</label>

A CSS Adapter may be able to remove the span around the checkbox/label, but I haven't seen one for that purpose.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • I've had to use this approach when the tags were getting in my way. – egrunin Jan 31 '10 at 21:16
  • 1
    I could use the tag tag directly, however our derived CheckBox includes a Command Event which may be used. Ideally we would like to solve this within the WebControl. – Mark Redman Jan 31 '10 at 21:27
  • @Mark - If that's not an option, you could inherit from Checkbox, over-write the rendering, or call it's `SetRenderMethodDelegate()` method. Rick Strahl has a rundown of it here: http://www.west-wind.com/Weblog/posts/6138.aspx – Nick Craver Jan 31 '10 at 22:02
1

Why don't you remove the span using .remove with jquery ?

Hannoun Yassir
  • 20,583
  • 23
  • 77
  • 112
  • 1
    Because the `` wraps the `` tag, which would be very inefficient to do correctly. – Dan Herbert Jan 31 '10 at 21:21
  • 2
    Although I like jQuery a lot and it could solve the problem, I would prefer solving the problem at a lower level which will be more efficient. – Mark Redman Jan 31 '10 at 21:23
1

Can you use a literal control instead? There's a big difference between these two alternatives:

<p>12345<asp:Label ID="lblMiddle" runat="server" Text="6"></asp:Label>7890</p>
<p>12345<asp:Literal ID="ltlMiddle" runat="server" Text="6"></asp:Literal>7890</p>
Bradbox
  • 11
  • 1
1

$(document).ready(function() {
  /* remove the relative spam involving inputs disabled */
  $('input[type="checkbox"]').parent('.aspNetDisabled').each(function() {
    var $this = $(this);
    var cssClass = $this.attr('class');
    $this.children('input[type="checkbox"]').addClass(cssClass).unwrap().parent('label[for],span').first().addClass('css-input-disabled');
  });
});
/* CSS Example */
.css-input {
  position: relative;
  display: inline-block;
  margin: 2px 0;
  font-weight: 400;
  cursor: pointer;
}
.css-input input {
  position: absolute;
  opacity: 0;
}
.css-input input:focus + span {
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
}
.css-input input + span {
  position: relative;
  display: inline-block;
  margin-top: -2px;
  margin-right: 3px;
  vertical-align: middle;
}
.css-input input + span:after {
  position: absolute;
  content: "";
}
.css-input-disabled {
  opacity: .5;
  cursor: not-allowed;
}
.css-checkbox {
  margin: 7px 0;
}
.css-checkbox input + span {
  width: 20px;
  height: 20px;
  background-color: #fff;
  border: 1px solid #ddd;
  -webkit-transition: background-color 0.2s;
  transition: background-color 0.2s;
}
.css-checkbox input + span:after {
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  font-family: "FontAwesome";
  font-size: 10px;
  color: #fff;
  line-height: 18px;
  content: "\f00c";
  text-align: center;
}
.css-checkbox:hover input + span {
  border-color: #ccc;
}
.css-checkbox-primary input:checked + span {
  background-color: #5c90d2;
  border-color: #5c90d2;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- Generate from asp.net -->
<label for="CheckBox1" id="Label4" class="css-input css-checkbox css-checkbox-primary">
  <span class="aspNetDisabled">
    <input id="CheckBox1" 
           type="checkbox" 
           checked="checked" 
           disabled="disabled">
  </span>
  <span></span>Disabled
</label>
  • The answer can become more valuable if you added some explanation and links to documentation, so the original poster and other users can actually learn from it. – Markus Safar Feb 11 '16 at 16:50
0

Try adding a constructor to your class that looks like this:

public MyControl() : base() 
{
}

If you notice, controls will render as spans as default since that's what the "WebControl" uses (if you use Reflector) :

protected WebControl() : this(HtmlTextWriterTag.Span) { }

Reference: http://aspnetresources.com/blog/stripping_span_from_webcontrol

turtlepick
  • 2,694
  • 23
  • 22
0

i wonder, is there a reason no1 mentioned this:

public MyControl() : base(string.Empty)

i got this reading http://aspnetresources.com/blog/stripping_span_from_webcontrol that flaviotsf mentioned

bresleveloper
  • 5,940
  • 3
  • 33
  • 47
0
                <div class="onoffswitch">
                     <asp:CheckBox ID="example1" runat="server" AutoPostBack="true" OnCheckedChanged="chkWifiRequired_CheckedChanged" CssClass="aspNetDisabled onoffswitch-checkbox"/>
                    <label class="onoffswitch-label" for='<%= example1.ClientID.ToString() %>'>
                        <span class="onoffswitch-inner"></span>
                        <span class="onoffswitch-switch"></span>
                    </label>
                </div>
            /* remove the relative spam involving inputs disabled */
            $('input[name=""]').parent('.aspNetDisabled').each(function () {
                var $this = $(this);
                var cssClass = "onoffswitch-checkbox";
                $('input[name=""]').addClass(cssClass).unwrap().parent('label[for],span').first().addClass('onoffswitch-checkbox');
            });

This will allow you to use the check box normally, still have it call server side code, and use the toggle from bootstrap. (I'm using the Inspina theme but it should be the same format for other toggles)

Audreth
  • 67
  • 5
0

I just had this issue and used Jon's answer, which is good and it works. The downside is that your class is defined within the codebehind and not your markup.

So I took the answer and made a progamatic way to retrieve all attributes for the control, copy them to InputAttributes and remove those copied attributes from attributes.

Note that while this extends from RadioButton, you could use the method to extend any control, such as labels or checkboxes.

using System.Web.UI;
using System.Web.UI.WebControls;

namespace Hidistro.UI.Common.Controls
{
    /// <summary>
    /// Just like a normal RadioButton, except that the wrapped span is disabled.
    /// </summary>
    public class CleanRadioButton : RadioButton
    {
        protected override void Render(HtmlTextWriter writer)
        {
            List<string> keysToRemove = new List<string>();

            foreach (object key in Attributes.Keys)
            {
                string keyString = (string)key;
                InputAttributes.Add(keyString, Attributes[keyString]);
                keysToRemove.Add(keyString);
            }

            foreach (string key in keysToRemove)
                Attributes.Remove(key);

            base.Render(writer);
        }
    }
}

This way, all you need to do is the following, and it will output tags without the span.

<namespace:CleanRadioButton class="class1" />
<namespace:CleanRadioButton class="class2" />

HTML output: (note that "generated" is autogenerated)

<input id="generated" type="radio" name="generated" value="generated" class="class1">
<input id="generated" type="radio" name="generated" value="generated" class="class2">
ChrisBeamond
  • 131
  • 4