Inline Recursion in ASP.NET Template to Print a Tree’s Node List

Posted in ASP.NET, C#

Here’s a neat & clean way to perform a recursion in ASP.NET, inside the .aspx/.ascx file. Suitable for ASP.NET MVC as well as WebForms.

No <asp:Repeater> + OnItemDataBound event, TreeView or concatenating strings recursively in the code behind involved.

Data Structure and Recursive Data Sample

public class NodeList : List<Node> {
}
public class Node {
	public string Name { get; set; }
	public NodeList Children { get; set; }
}
public class Repository {
	public static NodeList GetNodes() {
		return new NodeList {
			new Node { Name = "1",
				Children = new NodeList {
					new Node { Name = "1.1" },
					new Node { Name = "1.2",
						Children = new NodeList {
							new Node { Name = "1.2.1" }
						}
					},
					new Node { Name = "1.3" },
					new Node { Name = "1.4" },
				}
			},
			new Node { Name = "2",
				Children = new NodeList {
					new Node { Name = "2.1" }
				}
			},
			new Node { Name = "3" }
		};
	}
}

The Recursive Function

<%
Action<NodeList, int> printNodesRecursively = null;
printNodesRecursively = (NodeList nodeList, int depth) => {
	if (nodeList==null || nodeList.Count==0) return;
%>
	<ul class="node-list depth-<%=depth%>">
<%
	foreach (Node node in nodeList) {
	%>
	<li>
		<%=node.Name%>
		<%printNodesRecursively(node.Children, depth + 1);%>
	</li>
	<%
	}
%>
    </ul>
<%
};
NodeList nodes = Repository.GetNodes(); // Or ViewData use for ASP.NET MVC
printNodesRecursively(nodes, 0);
%>

Notice: The printNodesRecursively function is declared with the value of null at first. Otherwise, the compiler says that the inner printNodesRecursively call is made on an unassigned variable.

This will basically print a <ul> with an <li> for each node, and inside each <li>, another <ul> with its children, recursively.

Notice the extra “depth” which indicates the current depth level in the tree inside the printNodesRecursively function. In this example it adds a special class to each level.

The Output

<ul class="node-list depth-0">
	<li>1
		<ul class="node-list depth-1">
			<li>1.1</li>
			<li>1.2
				<ul class="node-list depth-2">
					<li>1.2.1</li>
				</ul>
			</li>
			<li>1.3</li>
			<li>1.4</li>
		</ul>
	</li>
	<li>2
		<ul class="node-list depth-1">
			<li>2.1</li>
		</ul>
	</li>
	<li>3</li>
</ul>

(Code re-indented manually :) )

Links^2 – September 13th, 2010

Posted in Links
  • The Official Guide to HTML5 Boilerplate
  • Stylebot – a Chrome extension that lets you customize any site’s CSS, like Firefox’s Stylish, or a Greasemonkey for CSS. Great WYSIWYG UI.
  • Firefox 4.0 beta 5 – I’ve been using FF 4 since beta 2, and I’m very pleased. In order to have all add-ons skip the version check, go to the url about:config, create a new boolean key named extensions.checkCompatibility.4.0b with the value of false. Restart FF and most of the add-ons will work.
  • CSS3 Playground - Yet another CSS3 WYSIWYG
  • SmartGit – A UI client for Git. Available for Mac/Windows/Linux

Elad Ossadon
September 13th, 2010
2 Comments »

JS/DOM AHA Moment: getElementsByTagName Collection is Always Up to Date According to the Current DOM Tree

Posted in DOM, JavaScript

Today I found out something interesting about getElementsByTagName. This method is quite popular, it returns all elements of a requested tag under a specific parent element.

The type which is returned out of a getElementsByTagName call is NodeList, which is not exactly an Array, but is enumerable and has the length property.

When you call document.getElementsByTagName("div") you get a NodeList of all div tags, but it seems that every time you use this variable, it shows an up to date list.

Meaning – if you have a NodeList instance of all divs on the document and then you dynamically add more divs to the document, this instance will contain all the new divs as well. Same for removed divs.

Test Case:

<div></div>
<div></div>
<div></div>
<div></div>
var divs=document.getElementsByTagName("div");
console.log("divs.length="+divs.length); // 4
document.body.appendChild(document.createElement("div"));
document.body.appendChild(document.createElement("div"));
document.body.appendChild(document.createElement("div"));
console.log("divs.length="+divs.length); // 7
document.body.removeChild(divs[0]);
console.log("divs.length="+divs.length); // 6

How to Maintain the Original Collection?

Simply, by creating a new Array out of the NodeList‘s contents:

var divs=document.getElementsByTagName("div");
divs=Array.prototype.slice.call(divs);
// the above is a shortcut to:
// var tmp=[];
// for (var i=0,l=divs.length;i<l;i++) tmp.push(divs[i]);
// divs=tmp;

MooTools, jQuery, Prototype etc. do not return a NodeList out of their DOM selector engines. They return an Array instance, so no need to worry about this.

This also applies to getElementsByClassName and getElementsByName, but not to querySelectorAll.

I investigated a bit inside the WebKit’s source and it seems like that the getElementsByTagName / getElementsByClassName / getElementsByName methods return a DynamicNodeList while the querySelectorAll method returns StaticNodeList.

CSS: Stretch a Box to its Parent’s Bounds

Posted in CSS

Not so famous, yet powerful feature of absolute positioning is stretching a box. Absolute positioning lets us having a box positioned according to the bounds of the closest relative/absolute/body parent (also known as offset parent).

The most popular use is having a box positioned in either top or bottom and right or left coordinates, and the dimensions of this box are defined by its inner content or a specific width/height.

Example #1 – Absolute Inside Relative, With Fixed Dimensions

<div class="relative">
    <div class="absolute"></div>
</div>
.relative {
    position:relative;
    width:100px; height:80px;
    background-color:#6E919A;
}
.absolute {
    position:absolute; top:10px; left:10px;
    width:30px; height:50px;
    background-color:#9BC9D1;
}

But what if you don’t know the dimensions of the parent, or don’t want to maintain the pixels twice on both parent and absolute child?

A height:100% value can be applied only for specific situations: The inner box should be the exact same height as its parent, start at the top and end at the bottom, no offsets. If a margin is applied, the inner box will just be moved but the height will stay the same, hence it will overflow. If a padding is applied, the height of the box will get bigger, and the box will also overflow.

The Solution

The less famous use is to omit width or height of the absolute positioned element and use a combination of top and bottom or left and right, which will cause our box to stretch between the bounds of the offset parent.

Example #2 – Absolute Inside Relative Without a Specific Height: The Absolute Stretches to the Relative’s Bounds

<div class="relative">
     xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx
    <div class="absolute"></div>
</div>
.relative {
    position:relative;
    width:100px;
    background-color:#6E919A;
}
.absolute {
    position:absolute; top:10px; bottom:20px; left:10px;
    width:30px;
    background-color:#9BC9D1;
}

What is it Good For?

So many things!

  • If you need 100% width or height for a div but you have padding/border that aren’t counted in the 100%, and therefore the 100% exceeds the parent – use top:0 and bottom:0 with a padding. Example (can be also solved with box-sizing, which isn’t supported by IE8).
  • If you need a designed scroll bar, and it should be as high as its parent’s height, but should also start from a certain offset: top:5px; right:5px; bottom:5px; width:20px; will fix its position. Example.
  • Sticky header and footer, by stretching the content area from header’s end to footer’s start. Example:
<div class="header">header</div>
<div class="content">
xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>
xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>
xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>
xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx
</div>
<div class="footer">footer</div>
.header {
    position:absolute; top:0; left:0; right:0;
    height:20px;
    background-color:#6E919A;
}
.content {
    position:absolute; top:20px; bottom:20px; right:0; left:0;
    background-color:#9BC9D1;
    overflow:auto;
}
.footer {
    position:absolute; bottom:0; left:0; right:0;
    height:20px;
    background-color:#6E919A;
}
  • If you still can’t use border image and other CSS3 goodies, and you have a designed box with image edges – you can use this method to stretch the top/bottom/left/right frame parts, but up to the corners. Example:
<div class="relative">
    xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx<br/>xxxxx
    <div class="corner left-top"></div>
    <div class="corner right-top"></div>
    <div class="corner left-bottom"></div>
    <div class="corner right-bottom"></div>
    <div class="frame top"></div>
    <div class="frame right"></div>
    <div class="frame bottom"></div>
    <div class="frame left"></div>
</div>​
.relative {
    position:relative;
    width:100px;
    background-color:#6E919A;
    padding:20px;
}
.corner {
    position:absolute;
    width:15px; height:15px; overflow:hidden;
    background-color:#9BC9D1;
}
.corner.left-top { left:0; top:0; }
.corner.right-top { right:0; top:0; }
.corner.left-bottom { left:0; bottom:0; }
.corner.right-bottom { right:0; bottom:0; }
.frame {
    position:absolute; overflow:hidden;
    background-color:#455A5F;
}
.frame.top { height:15px; top:0; right:15px; left:15px; }
.frame.right { width:15px; right:0; top:15px; bottom:15px; }
.frame.bottom { height:15px; bottom:0; left:15px; right:15px; }
.frame.left { width:15px; left:0; top:15px; bottom:15px; }

Share your examples in the comments.

Links^2 – Aug 22nd, 2010

Posted in Links



Page optimized by WP Minify WordPress Plugin