A Quirk of Controls in ASP.Net

As part of the legacy codebase I’m working with at the moment I have recently been required to edit a product listing page to do something simple; add an extra link underneath each product.

 

Interestingly enough the product listing page is constructed as a collection of System.Web.UI.Controls, generating an HTML structure directly in C# which is then styled after being rendered completely flat.

 

For example:, each item in the listing could look a bit like this

public class CodeControl : Control 
{ 
    protected override void CreateChildControls() 
    { 
        AddSomeStuff(); 
    }

    private void AddSomeStuff() 
    { 
        var image = new Image 
        { 
            ImageUrl = "http://memegenerator.net/cache/instances/250x250/8/8904/9118489.jpg", 
            Width = 250, 
            Height = 250 
        }; 
        Controls.Add(image);

        var hyperlink = new HyperLink { NavigateUrl = "http://memegenerator.net/", Text = "Business Cat" }; 
        Controls.Add(hyperlink);

        var title = new HtmlGenericControl(); 
        title.Attributes.Add("class", "title"); 
        title.InnerText = "£19.99"; 
        Controls.Add(title); 
    } 
}

 

And then the code to render it would be something like:

private void PopulateContainerDiv() 
{ 
    var ul = new HtmlGenericControl("ul");

    for (var i = 0; i < 10; i++) 
    { 
        // setup html nodes 
        var item = new CodeControl(); 
        var li = new HtmlGenericControl("li");

        // every 3rd li reset ul 
        if (i % 3 == 0) ul = new HtmlGenericControl("ul");

        // add item to li 
        li.Controls.Add(item);

        // add li to ul 
        ul.Controls.Add(li);

        // add ul to div 
        containerDiv.Controls.Add(ul); 
    } 
}

The resulting HTML looks like:

<ul><li><img src="http://memegenerator.net/cache/instances/250x250/8/8904/9118489.jpg" style="height:250px;width:250px;" /><a href="http://memegenerator.net/">Business Cat</a><span class="title">&#163;19.99</span></li>
.. snip..

And the page itself:

232111_codecontrol_blank_unstyled

I’ve never seen this approach before, but it does make sense; define the content, not the presentation. Then to make it look nicer we’ve got some css to arrange the list items and their content, something like:

ul { list-style:none; overflow: hidden; float: none; }
li { padding-bottom: 20px; float: left; }
a, .title { display: block; }

Which results in the page looking a bit more like

232111_codecontrol_blank_styled

 

So that’s enough background on the existing page. I was (incorrectly, with hindsight, but that’s why we make mistakes right? How else would we learn? *ahem*..) attempting to implement a change that wrapped the contents of each li in a tag so that some jQuery could pick up the contents of that li and put them somewhere else on the page when a click was registered within the li.

So I did this:

// setup html nodes
var item = new CodeControl();
var li = new HtmlGenericControl("li");
var form = new HtmlGenericControl("form");

// every 3rd li reset ul
if (i % 3 == 0) ul = new HtmlGenericControl("ul");

// add item to form
form.Controls.Add(item);

// add form to li
li.Controls.Add(form);

// add li to ul
ul.Controls.Add(li);

// add ul to div
containerDiv.Controls.Add(ul);

I added in a <form> tag and put the control in there, then put the form in the li and the li in the ul. However, this resulted in the following HTML being rendered:

232111_codecontrol_elem_form

Eh? Why does the first <li> not have a <form> in there but the rest of them do? After loads of digging around my code and debugging I just tried something a bit random and changed it from a <form> to a <span>:

// setup html nodes
var item = new CodeControl();
var li = new HtmlGenericControl("li");
var wrapper = new HtmlGenericControl("span");

// every 3rd li reset ul
if (i % 3 == 0) ul = new HtmlGenericControl("ul");

// add item to form
wrapper.Controls.Add(item);

// add form to li
li.Controls.Add(wrapper);

// add li to ul
ul.Controls.Add(li);

// add ul to div
containerDiv.Controls.Add(ul);

Resulting in this HTML:

232111_codecontrol_elem_span

Wha? So if I use a <span> all is good and a <form> kills the first one? I don’t get it. I still don’t get it, and I’ve not had time to dig into it. in the end I just altered the jQuery to look for closest(‘span’) instead of closest(‘form’) and everything was peachy.

 

If anyone knows why this might happen, please do comment. It’s bugging me.

Leave a Reply

Your email address will not be published. Required fields are marked *