Monday, January 12, 2009

Use a single event to traverse back and forth between server-side and client-side 2 times to complete a task

I placed a UltraWebTree in a Usercontrol(.ascx) file, and used a (.cs) file to handle event and logic. Then, reference a Javascript where I handled the client side events. I had to add a new node to a tree from client-side, rename it, add it into the database from server-side, then select it from the client side, and go back to server side to open folder associated with that new node. I did these in 4 steps:

Step1. Create a new node from client side, rename it:

Add this code into the Javascript file to add a new node:

var currentNodeId;
var newNodeAdded = false;
var newNodeId;

function addChild() {
var tree = igtree_getTreeById(UltraWebTreeClientID);
var node = tree.getNodeById(currentNodeId);
if (node.hasChildren()) {
if (node.getExpanded() == false) {
node.setExpanded(true);
}
}
if (node) {
newnode = node.addChild(newFolderName);
newNodeId = newnode.Id;
newnode.edit();
newNodeAdded = true;
}
}

CurrentNodeID is the id of the node that is currently selected taken from the nodeSelectionChanged mathod. UltraWebTreeClientID is the id of the tree that was passed from the (.cs) file's pageLoad section's If(!Page.isPostback) portion:

String Script = "var UltraWebTreeClientID = '" + UltraWebTree1.ClientID.Replace("_", "") + "';";
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "InitVariable", Script, true);


Step2: Go back to server-side to add a record into the DB:

After a new node has been added, the nodeAdded event will be fired, which you need to handle:

void UltraWebTree1_NodeAdded(object sender, Infragistics.WebUI.UltraWebNavigator.WebTreeNodeEventArgs e)
if (uxTreeEventLog.Text == "")
{
TreeNodeChangedArgs args = new TreeNodeChangedArgs();
args.Name = e.Node.Text;
args.Parent = e.Node.Parent.Tag.ToString();
args.TreeNodeAction = TreeNodeChangeAction.Added;
if (TreeNodeChanged != null)
TreeNodeChanged(sender, args);
e.Node.DataKey = Convert.ToInt32(args.ID);
e.Node.Tag = Convert.ToInt32(args.ID);
}

TreeNodeChangedArgs is a class declared globally to handle the event properties:


public class TreeNodeChangedArgs
{
public String ID;
public String Name;
public String Parent;
public TreeNodeChangeAction TreeNodeAction;
public Boolean Cancel;
}

TreeNodeChangedAction is an enum declared globally:


public enum TreeNodeChangeAction
{
Added,
Changed,
Removed
}

TreeNodeChange is a variable of a deligate also declared globally:

public delegate void TreeNodeChangedEventHandler(object sender, TreeNodeChangedArgs e);
public TreeNodeChangedEventHandler TreeNodeChanged;

It will take the event outside the usercontrol and let you handle the event from the page where you have placed this usercontrol. There you will add a new record using Business Layer in the DB taking info of the node (ex: id, name, parent, etc...) that was passed from here.

Step 3: Go back to client-side to select the node:

To go back to client-side again, you need to use end request method from the (.cs) file's pageLoad section's If(!Page.isPostback) portion:

this.Page.ClientScript.RegisterStartupScript(this.GetType(), "RegisterFunciton", "Sys.WebForms.PageRequestManager.getInstance().add_endRequest(TreeControl_EndRequestHandler);", true);

Now, you need to write a function in the javascript file with the name TreeControl_EndRequestHandler:

function TreeControl_EndRequestHandler(sender, args) {
if (newNodeAdded == true) {
var tree = igtree_getTreeById(UltraWebTreeClientID);
var node = tree.getNodeById(newNodeId);
node.setSelected(true);
newNodeAdded = false;
}
}

Step 4: Open associated folder from server-side:

After selecting the new node from the client-side, the selectionChanged event will be fired which you have to handle in the (.cs) file:


void UltraWebTree1_NodeSelectionChanged(object sender, WebTreeNodeEventArgs e)
{
if (NodeClicked != null)
NodeClicked(sender, e);
}

Again, NodeClicked is a variable of a delicate that was declared globally:

public delegate void NodeClickedEventHandler(object sender, WebTreeNodeEventArgs e);
public NodeClickedEventHandler NodeClicked;

You can take the event outside of this control and handle it on the page, where you can search for associate folder in the DB, and open it (in a different panel beside to the tree)

Step 5: Create chain effect:

If you have a debugging point set at the TreeControl_EndRequestHandler function, then you will notice that the process has come back to client-side again. In fact, after every server-side events, process will come back to here, from where you can chain it back to server side again.

Most part of this code(server-side part) was done by Ranku vai (Anupam Ranku, Senior Software Engineer, Bording Vista Ltd.) Thank you very much, Ranku vai.

2 comments:

andy said...

Hi

Thanks for such a great post. I have a quick question, I am calling addChild() method in my javascript code and its getting called during the webtree drop event, but its not firing the webtree nodeadded event on the server side at all. Following is my drop event. Could you please help me with that. Thanks

function uwt_FolderTree_Drop(oTree, oNode, oDataTransfer, oEvent)
{
var sourceNode = oDataTransfer.sourceObject;
if(!oNode.isChildOf(sourceNode))
{
//oNode.addChild(oDataTransfer.dataTransfer.getData("Text"));
AddChildNodesRecursive(sourceNode,oNode);
oNode.setExpanded(true);
if(sourceNode)
sourceNode.remove();
}
return false;
}

function AddChildNodesRecursive(childNode, parentNode)
{
var newChild = parentNode.addChild(childNode.getText());
if (childNode.hasChildren())
{
var children = childNode.getChildNodes();
for (c in children)
{
var childSubNode = children[ c ];
AddChildNodesRecursive(childSubNode, newChild);
}
}
}

cosmicice said...

Hello andy, sorry for such a late reply. I was away from blogging for a long time. Anyways, if you havent found a solution already, Check whether autopostback is set to true for ultrawebtree (from the design page). And check autopostback flag, too:
<AutoPostBackFlags NodeChanged="True" NodeDropped="true" />

If you want to keep autopostback set false and still want to postback, then use this code at the bottom of your function:

igtree_needPostBack(UltraWebTreeClientID);
var ts = igtree_treeState[UltraWebTreeClientID];
__doPostBack(ts.UniqueId, oNode.element.id + ":Update");

addchild() method should hit both NodeAdded and NodeChanged events of server side if postback occurs.