Update: The javascript on this blog has been suppressed by the blogger's parser. Consequently, some of the functionality may not work. Inconvenience is regretted.

Wednesday, June 20, 2007

Asp.Net Viewstate

One of the most neglected(in terms of understanding) and most used(functionally) features of asp.net is Viewstate. Most of the times the asp.net developer keep using viewstate feature as a black box. I don't need to tell you Viewstate can make hell lot of difference in the performance of your site, IF USED PROPERLY.

The other day i stumbled upon an excellent article that tells you everything you need to know about asp.net viewstate. Check it out here: http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx

Happy Programming!!

Monday, June 18, 2007

Firefox is the way to go..

This one is for those of you who have not yet embraced Mozilla's great browser Firefox. Firefox is designed for speed and security and i can assure you once you experience the power of fifefox you'll not try anything else again. Yes, the new browser from Microsoft, Internet Explorer 7 has introduced some good features besides mimicking Firefox's Tabbed Interface but it still sucks when it comes to speed. IE7 gets frustratingly slow if you open up a few tabs. Besides, firefox is having some great add-ons(out of hundreads of add-ons available) that you would just love.

Few of my favourite ones are:

Cooliris Previews: This add-on allows you to preview links on a page, i.e., you can view pages pointed to by the links on the current page, directly inside your current page without leaving it.

IE Tab: Some sites render properly only in IE and they would have imperfect appearance in Firefox(experienced this with MSDN site a lot). Now we have a great add-on called IE Tab that embeds IE directly in the firefox tabs. In effect IE's rendering engine is used for the sites you would like to open in IE.

FoxMarks: Take your bookmarks wherever you go.

Finally, if you are a web developer Firebug is indispensable.

Folks, don't miss this great experience anymore...go and install Firefox.

Wednesday, June 13, 2007

Getting TreeNode values on the client side with javascript

In a lot of scenarios it is required to get the value of a treenode (for an asp.net treeview) on the client side. While on the server we can get the nodevalue directly via the Value property of the Treenode, on the client it seems there is no corresponding attribute added to the anchor(yes treenodes are rendered as anchor(<a ..) tags) . Getting the node's text is easy - just get hold of the node's anchor element and call its innerText property. But how do we get the node value? Well, if you look closely at the rendered HTML for the node, you could find the node value lurking inside the href property for the node (provided you have not set the NavigateUrl property for the node manually). Something like:

href="javascript:__doPostBack('TreeView1','sRoot\\firstChild\\...\\nodeValue')"

All we have to do is to extract that bold part from what the href property gives us.
Whereas there may be various scenarios where we may need the node value on the client, I would demonstrate it for the case of the node click itself - you want the value when you click a treenode. Try this:

1) Add an attribute to the treeview in code behind as:

if (!IsPostBack)
{
TreeView1.Attributes.Add("onclick", "return OnTreeClick(event)");
}


2) Put the below code in head tag of .aspx page
Oops!! The current security settings of your browser do not allow the scripts on the page to access your clipboard.If you are using mozilla firefox, you may change security settings as follows: Type about:config in the url bar and set signed.applets.codebase_principal_support to true. For more info, check here or contact blog author.
 

<script type="text/javascript">
function OnTreeClick(evt) {
var src = window.event != window.undefined ? window.event.srcElement : evt.target;
var nodeClick = src.tagName.toLowerCase() == "a";
if (nodeClick) {
//innerText works in IE but fails in Firefox (I'm sick of browser anomalies), so use innerHTML as well
var nodeText = src.innerText || src.innerHTML;
var nodeValue = GetNodeValue(src);
alert("Text: " + nodeText + "," + "Value: " + nodeValue);
}
return false; //comment this if you want postback on node click
}
function GetNodeValue(node) {
var nodeValue = "";
var nodePath = node.href.substring(node.href.indexOf(",") + 2, node.href.length - 2);
var nodeValues = nodePath.split("\\");
if (nodeValues.length > 1)
nodeValue = nodeValues[nodeValues.length - 1];
else
nodeValue = nodeValues[0].substr(1);

return nodeValue;
}
</script>


Another scenario i can think of is when you have check boxes in the treeview and you want to get the nodevalue for the node that is checked. In that case you can just get the checkbox ( rendered as input tag) element first and then you can get the reference to the node via the nextSibling property for the checkbox.

That's all. Hope this is helpful.

pushp

Tuesday, June 5, 2007

Client Side Expand/Collapse All Nodes For ASP.NET 2.0 Treeview

The asp.net treeview provides a lot of features/functions, one of which is the Expand/Collapse All functionality on the server side. The Treeview Control has got two function for doing just that: TreeView.ExpandAll(), TreeView.CollapseAll(). But going to server to accomplish such a simple functionality seemed a little odd to me. So, I wrote some javascript that does precisely the same. Checkout the below script:

Oops!! The current security settings of your browser do not allow the scripts on the page to access your clipboard.If you are using mozilla firefox, you may change security settings as follows: Type about:config in the url bar and set signed.applets.codebase_principal_support to true. For more info, check here or contact blog author.
 

function TreeviewExpandCollapseAll(treeViewId, expandAll)
{
var displayState = (expandAll == true ? "none" : "block");
var treeView = document.getElementById(treeViewId);
if(treeView)
{
var treeLinks = treeView.getElementsByTagName("a");
var nodeCount = treeLinks.length;

for(i=0;i<nodeCount;i++)
{
if(treeLinks[i].firstChild.tagName)
{
if(treeLinks[i].firstChild.tagName.toLowerCase() == "img")
{
var currentToggleLink = treeLinks[i];
var childContainer = GetParentByTagName("table", currentToggleLink).nextSibling;
if (childContainer.style.display == displayState)
{
eval(currentToggleLink.href);
}
}
}
}//for loop ends
}
}

//utility function to get the container of an element by tagname
function GetParentByTagName(parentTagName, childElementObj)
{
var parent = childElementObj.parentNode;
while(parent.tagName.toLowerCase() != parentTagName.toLowerCase())
{
parent = parent.parentNode;
}
return parent;
}


Get Formatted Version Of Above Script

The above script could be used as:


<a href="javascript:TreeviewExpandCollapseAll('<%=TreeView1.ClientID%>', true)">Expand All</a>
<a href="javascript:TreeviewExpandCollapseAll('<%=TreeView1.ClientID%>', false)">Collapse All</a>
<asp:TreeView ID="TreeView1" .....................



That's all there is to it.

Hope this is helpful.

Update (7/25/2008): The script has been updated to fix a minor bug concerning the toggle images being screwed up if ShowLines is false for the treeview. Thanks to comments from users, particularly to ryan.

pushp

Monday, June 4, 2007

Asp.Net 2.0 Treeview Checkbox Check/Uncheck All script

Its a very common requirement to have the parent-child check behaviour in asp.net treeview. To define the problem:
1)Check all the child nodes if the parent is checked and uncheck all child nodes if parent is unchecked ( well, this part is simple).
2)If a node at any level is checked and all its siblings are already checked then the parent node should be checked and the same should apply for the parent node(i.e., if its siblings are checked....), this should happen till the root node.
3)If a node at any level is unchecked then the parents( ma, grand ma, grand grand ma....) up to the root node must be unchecked.

Well there have been scripts on the net that only half accomplished the task(check footnotes). So I wrote the script that solves the problem completely, upto best of my knowledge. I've tested in IE 7 and Firefox 2.0, hope it works fine for you all.

Here's how to implement it:

Step 1: In the page load in code behind file add an attribute to the treeview as:

If(!isPostBack)
{
    TreeView1.Attributes.Add("onclick","OnTreeClick(event)");
}

The desired affect could also be accomplished by direclty adding the attribute to the treeview tag in .aspx file as: <asp:treeview onclick="OnTreeClick(event)"... which would cause Visual Studio to display a warning but it works anyway but the codebehind way of doint it is the right way.

Step 2: Put the below script in the head section of your .aspx page:

Oops!! The current security settings of your browser do not allow the scripts on the page to access your clipboard.If you are using mozilla firefox, you may change security settings as follows: Type about:config in the url bar and set signed.applets.codebase_principal_support to true. For more info, check here or contact blog author.
 

function OnTreeClick(evt)
{
var src = window.event != window.undefined ? window.event.srcElement : evt.target;
var isChkBoxClick = (src.tagName.toLowerCase() == "input" && src.type == "checkbox");
if(isChkBoxClick)
{
var parentTable = GetParentByTagName("table", src);
var nxtSibling = parentTable.nextSibling;
//check if nxt sibling is not null & is an element node
if(nxtSibling && nxtSibling.nodeType == 1)
{
if(nxtSibling.tagName.toLowerCase() == "div") //if node has children
{
//check or uncheck children at all levels
CheckUncheckChildren(parentTable.nextSibling, src.checked);
}
}
//check or uncheck parents at all levels
CheckUncheckParents(src, src.checked);
}
}

function CheckUncheckChildren(childContainer, check)
{
var childChkBoxes = childContainer.getElementsByTagName("input");
var childChkBoxCount = childChkBoxes.length;
for(var i=0;i<childChkBoxCount;i++)
{
childChkBoxes[i].checked = check;
}
}

function CheckUncheckParents(srcChild, check)
{
var parentDiv = GetParentByTagName("div", srcChild);
var parentNodeTable = parentDiv.previousSibling;
if(parentNodeTable)
{
var checkUncheckSwitch;
if(check) //checkbox checked
{
var isAllSiblingsChecked = AreAllSiblingsChecked(srcChild);
if(isAllSiblingsChecked)
checkUncheckSwitch = true;
else
return; //do not need to check parent if any(one or more) child not checked
}
else //checkbox unchecked
{
checkUncheckSwitch = false;
}

var inpElemsInParentTable = parentNodeTable.getElementsByTagName("input");
if(inpElemsInParentTable.length > 0)
{
var parentNodeChkBox = inpElemsInParentTable[0];
parentNodeChkBox.checked = checkUncheckSwitch;
//do the same recursively
CheckUncheckParents(parentNodeChkBox, checkUncheckSwitch);
}
}
}

function AreAllSiblingsChecked(chkBox)
{
var parentDiv = GetParentByTagName("div", chkBox);
var childCount = parentDiv.childNodes.length;
for(var i=0;i<childCount;i++)
{
if(parentDiv.childNodes[i].nodeType == 1)
{
//check if the child node is an element node
if(parentDiv.childNodes[i].tagName.toLowerCase() == "table")
{
var prevChkBox = parentDiv.childNodes[i].getElementsByTagName("input")[0];
//if any of sibling nodes are not checked, return false
if(!prevChkBox.checked)
{
return false;
}
}
}
}
return true;
}

//utility function to get the container of an element by tagname
function GetParentByTagName(parentTagName, childElementObj)
{
var parent = childElementObj.parentNode;
while(parent.tagName.toLowerCase() != parentTagName.toLowerCase())
{
parent = parent.parentNode;
}
return parent;
}


Get Formatted Version Of Above Script

The script is pretty much self explanatory with function names saying it all.
Comments awaited.

Footnotes: There has been other scripts on the net that accomplished the job only partially, the one that reached closest to doing it could be found in this thread on asp.net forums, i too have posted my solution there.