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">£19.99</span></li> .. snip..
And the page itself:
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
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:
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:
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.