Sep
06
2007
JQuery tree viewer in ASP.NET
Posted by admin under
Ajax
Here's a ASP.NET and JQuery based tree viewer example. I'm using Jörn Zaefferers treeview for the javascript tree rendering for the simple reason it's completely unobtrousive. You mark the tree up by regular ul/li structure - meaning if someone doesn't have Javascript activated (say a search engine spider for one example) they will be still be presented with all the content and it's possible to follow links etc.
Here's the first demo - default.aspx in the download solution (VS 2005, C#):

Hey, you might think, lets just download jquery and the treeview plugin and I'm ready to use it. From reading the code it looks just like a matter of setting some unique id:s for each li and to start with one particular item selected you just $('#ctl00_ulAdminMenu_-1000').find('a:first').addClass('selected'); $('#ctl00_ulAdminMenu_-1000').addClass('open'); i.e set class as selected and open. This is true - for the root item that is. But if you want to start up with a deep item selected (and opened) you will need to explicitly set the open class for each parents as well. $('#ctl00_ulAdminMenu_-parent1').addClass('open'); $('#ctl00_ulAdminMenu_parent2').addClass('open'); $('#ctl00_ulAdminMenu_theitem').addClass('open'); So this sure makes this article worthwhile. I will give you a simple filebrowser (dynamic.aspx) which handles all that:


And here's the complete ASP.NET code:
protected void Page_Load(object sender, EventArgs e)
{
if ( !IsPostBack )
Button1_Click(null,null);
}
private string m_sIDToSelect = "";
private System.Collections.Generic.List<string> m_DirsToOpen = new System.Collections.Generic.List<string>();
private int m_nNum = 0;
private string SelectedResource
{
get
{
if (Request["resource"] == null || Request["resource"] == "")
return txtLocation.Text;
return Request["resource"];
}
}
//Returns true if selectiopn is somewhere below or inside
private bool AppendDir(System.Text.StringBuilder oBuilder, string sDir, bool bFirst )
{
bool bContainsSelection = false;
//Generate a safe id
string sIdDir = "li_res_" + m_nNum.ToString();
m_nNum++;
oBuilder.AppendLine(" <li id=\"" + sIdDir + "\">");
if (SelectedResource == sDir)
{
m_sIDToSelect = sIdDir;
m_DirsToOpen.Add(sIdDir);
bContainsSelection = true;
}
string sShowName = sDir;
if (bFirst == false)
{
System.IO.DirectoryInfo oInfo = new System.IO.DirectoryInfo(sDir);
sShowName = oInfo.Name;
}
oBuilder.AppendLine(" <img src=\"css/images/folder.gif\"/> <a href=\"dynamic.aspx?resource=" + sDir + "\">" + sShowName + "</a>");
oBuilder.AppendLine(" <ul>");
foreach (string sSubDir in System.IO.Directory.GetDirectories(sDir))
{
bool fOpen = AppendDir(oBuilder, sSubDir, false);
if (fOpen && bContainsSelection == false)
{
bContainsSelection = true;
m_DirsToOpen.Add(sIdDir);
}
}
foreach (string sFile in System.IO.Directory.GetFiles(sDir))
{
string sTheFile = System.IO.Path.GetFileName(sFile);
//Add file
string sSafeIDFile = sTheFile.Replace(".", "-");
sSafeIDFile = sSafeIDFile.Replace("\\", "_");
sSafeIDFile = sSafeIDFile.Replace("/", "_");
string sIdFile = "li_res_" + m_nNum.ToString();
if (SelectedResource == sFile)
{
m_sIDToSelect = sIdFile;
m_DirsToOpen.Add(sIdDir);
bContainsSelection = true;
}
m_nNum++;
oBuilder.AppendLine(" <li id=\"" + sIdFile + "\">");
oBuilder.AppendLine("<img src=\"css/images/file.gif\"/> ");
oBuilder.AppendLine("<a href=\"dynamic.aspx?resource=" + sFile + "\">" + sTheFile + "</a>");
oBuilder.AppendLine(" </li>");
}
oBuilder.AppendLine(" </ul>");
oBuilder.AppendLine(" </li>");
return bContainsSelection;
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Text.StringBuilder oBuilder = new System.Text.StringBuilder();
oBuilder.AppendLine("<ul id=\"ulAdminMenu\" class=\"dir\">");
AppendDir(oBuilder, txtLocation.Text, true);
oBuilder.AppendLine("</ul>");
//Read all and create a dynamic tree...
plTreeHolder.Controls.Add(new LiteralControl(oBuilder.ToString()));
//Append a selection script - might not be the best way, sgould be in header - but just to make it easy to follow:
oBuilder = new System.Text.StringBuilder();
oBuilder.AppendLine("<script type=\"text/javascript\">");
oBuilder.AppendLine("$(document).ready(function()");
oBuilder.AppendLine("{");
oBuilder.AppendLine("$('#" + m_sIDToSelect + "').find('a:first').addClass('selected');");
foreach( string sDirID in m_DirsToOpen )
oBuilder.AppendLine("$('#" + sDirID + "').addClass('open');");
oBuilder.AppendLine("$('#ulAdminMenu').Treeview({unique:true,collapsed:true});");
oBuilder.AppendLine("}");
oBuilder.AppendLine(");</script>");
Header.Controls.Add( new LiteralControl(oBuilder.ToString()) );
lblSelectedResource.Text = SelectedResource;
}
}
As for the ASP.NET code first I decided to do it easy. I build up the ul/li structure into a
StringBuilder and feed that string into a placeholder. But the interesting stuff is
private bool AppendDir(System.Text.StringBuilder oBuilder, string sDir, bool bFirst )
{
}
Basically it recursively calls itself with all it subdirs - and whenever (if) it finds the selected
file or directory it the dir into the list m_DirsToOpen - AND returns true.
The caller now knows the selected resource is somewhere below itself - so it adds itself to the same list
m_DirsToOpen
And when generating the javascript we go through the m_DirsToOpen list and generates javascript to
set the 'open' class for each of the items:
foreach( string sDirID in m_DirsToOpen )
oBuilder.AppendLine("$('#" + sDirID + "').addClass('open');");
As you sure already know I really like JQuery for my client side and Ajax development. It's relatively small (as compared to Ajax for ASP.NET) yet still really functional and there's a lot of third party plugins available. And another factor (when comparing to
other javascript frameworks ) - it's MIT licensed, which means you could ship it with commercial products if you'd like.
Attachments