Update 2/10/2009: I have updated the helper code a little bit to include an ID parameter as well as to inject the jQuery treeview script code automatically. Please modify to your desire, or make sure to include the jQuery TreeView plugin script to your page before running.
The following helper will make it easy to create a tree view from a recursive self-referencing table. Below you are seeing a tree of “Locations” where each Location can contain X number of child locations.
Dependencies
jQuery TreeView Plugin
Rendered Tree
Table Definition
The table itself is extremely simple, each Location has a ParentLocationId which is a relationship to the same table. If the ParentLocationId is null then it is a root location.
Usage
Simple
<%= Html.TreeView("locations",
Model.Locations,
l => l.ChildrenLocations,
l => l.Name) %>
Wrapping a div around each list item
<%= Html.TreeView("dropTree",
Model.Locations,
l => l.ChildrenLocations,
l => "<div class='dropZone'>" + l.Name + "<div>")
Making each list item an ActionLink
<%= Html.TreeView("dropTree",
Model.Locations,
l => l.ChildrenLocations,
l => Html.ActionLink("MyController", "MyAction", l.Name, new { id = l.Name })
The Code
public static class TreeViewHtmlHelper
{
/// <summary>
/// Create a TreeView of nodes starting from a root element
/// </summary>
/// <param name="treeId">The ID that will be used when the ul is created</param>
/// <param name="rootItems">The root nodes to create</param>
/// <param name="childrenProperty">A lambda expression that returns the children nodes</param>
/// <param name="itemContent">A lambda expression defining the content in each tree node</param>
public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> rootItems, Func<T, IEnumerable<T>> childrenProperty, Func<T, string> itemContent)
{
return html.TreeView(treeId, rootItems, childrenProperty, itemContent, true, null);
}
/// <summary>
/// Create a TreeView of nodes starting from a root element
/// </summary>
/// <param name="treeId">The ID that will be used when the ul is created</param>
/// <param name="rootItems">The root nodes to create</param>
/// <param name="childrenProperty">A lambda expression that returns the children nodes</param>
/// <param name="itemContent">A lambda expression defining the content in each tree node</param>
/// <param name="includeJavaScript">If true, output will automatically render the JavaScript to turn the ul into the treeview</param>
public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> rootItems, Func<T, IEnumerable<T>> childrenProperty, Func<T, string> itemContent, bool includeJavaScript)
{
return html.TreeView(treeId, rootItems, childrenProperty, itemContent, includeJavaScript, null);
}
/// <summary>
/// Create a TreeView of nodes starting from a root element
/// </summary>
/// <param name="treeId">The ID that will be used when the ul is created</param>
/// <param name="rootItems">The root nodes to create</param>
/// <param name="childrenProperty">A lambda expression that returns the children nodes</param>
/// <param name="itemContent">A lambda expression defining the content in each tree node</param>
/// <param name="includeJavaScript">If true, output will automatically render the JavaScript to turn the ul into the treeview</param>
/// <param name="emptyContent">Content to be rendered when the tree is empty</param>
/// <param name="includeJavaScript">If true, output will automatically into the JavaScript to turn the ul into the treeview</param>
public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> rootItems, Func<T, IEnumerable<T>> childrenProperty, Func<T, string> itemContent, bool includeJavaScript, string emptyContent)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("<ul id='{0}'>\r\n", treeId);
if(rootItems.Count() == 0)
{
sb.AppendFormat("<li>{0}</li>", emptyContent);
}
foreach (T item in rootItems)
{
RenderLi(sb, item, itemContent);
AppendChildren(sb, item, childrenProperty, itemContent);
}
sb.AppendLine("</ul>");
if (includeJavaScript)
{
sb.AppendFormat(
@"<script type='text/javascript'>
$(document).ready(function() {{
$('#{0}').treeview({{ animated: 'fast' }});
}});
</script>", treeId);
}
return sb.ToString();
}
private static void AppendChildren<T>(StringBuilder sb, T root, Func<T, IEnumerable<T>> childrenProperty, Func<T, string> itemContent)
{
var children = childrenProperty(root);
if(children.Count() == 0)
{
sb.AppendLine("</li>");
return;
}
sb.AppendLine("\r\n<ul>");
foreach (T item in children)
{
RenderLi(sb, item, itemContent);
AppendChildren(sb, item, childrenProperty, itemContent);
}
sb.AppendLine("</ul></li>");
}
private static void RenderLi<T>(StringBuilder sb, T item, Func<T, string> itemContent)
{
sb.AppendFormat("<li>{0}", itemContent(item));
}
}
Technorati Tags:
ASPNET MVC,
jQuery