开发者

How to remove span tag from WebControl when rendered

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?


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.


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.


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


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.


Using Jquery

<script>
        $(".selector input").unwrap().addClass("cssclass");
</script>


    protected override HtmlTextWriterTag TagKey
    {
        get
        {              
            return HtmlTextWriterTag.Div;
        }
    }

should do


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.


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


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>


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.


$(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>


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


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


                <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)


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">
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜