This is a migrated thread and some comments may be shown as answers.

Shift Click Multi-Select and Copy Node with Children Implementation

7 Answers 386 Views
TreeView
This is a migrated thread and some comments may be shown as answers.
Terry Hoiness
Top achievements
Rank 1
Terry Hoiness asked on 26 Oct 2010, 04:13 PM
I guess these aren't really problems per se, but I'd find it odd if I were the only one that wanted to see these fixes implemented, so I have decided to create a thread with a fix in the hopes that someone will clean it up and make it a permanent solution, and that I can help others with a similar problem implement the missing functionality.

So starting with shift click...

<body onkeydown="setShift(event)" onkeyup="setShift(event)">
  <telerik:RadCodeBlock runat="server" ID="RadCodeBlock1">
            <script type="text/javascript">   
               //I normally put this code right in the form (first item)
               var shiftKey=false;
               var treeView;
 
                function pageLoad()
                {
                    treeView = $find ("<%= treeYourTree.ClientID %>");
                }
 
               //capture the shift key for copying
               function setShift(e)
               {
                    if (window.event)
                    {
                        shiftKey = window.event.shiftKey;
                    }
                    else
                    {
                        if (e.shiftKey)
                        {
                            shiftKey=true;
                        }
                        else
                        {
                            shiftKey=false;
                        }
                    }
               }
 
               function onNodeClicked(sender, eventArgs)
               {             
                    if (shiftKey)
                    {
                        treeView.trackChanges();
                        //We should have selected nodes if we are shift clicking
                        if (treeView.get_selectedNodes!=null)
                        {
                            //Capture the first selected node and the current selected node
                            var firstSelected = treeView.get_selectedNodes()[0];
                            var currentSelected = eventArgs.get_node();
                            //Unselect all the nodes and initialize the continue / iteration boolean
                            treeView.unselectAllNodes;
                            var cont=false;
                             
                            //Iterate through the parent's children (iterate through the same level as selected)
                            for (var i=0; i< firstSelected.get_parent().get_nodes().get_count(); i++)
                            {
                                currItNode = firstSelected.get_parent().get_nodes().getNode(i);
                                cont = (cont)? !(currItNode == firstSelected || currItNode == currentSelected)
                                               :(currItNode == firstSelected || currItNode == currentSelected);
                                 
                               if (cont && firstSelected.get_parent().get_nodes().getNode(i))
                                        firstSelected.get_parent().get_nodes().getNode(i).select();
                            }
                             
                        }
                        treeView.commitChanges();
                    }
               }
     </script>
  </telerik:RadCodeBlock>
 
<-- tree goes somewhere in here with OnClientNodeClicked="onNodeClicked" -->
</body>
Pay special attention to body onkey events in my provided code.  This has been tested in IE and FireFox.

Known limitations:
  1.  When shift selecting from a child through another parent, it gets weird.  As it stands now, this allows shift selecting under the parent of the beginning of the first shift click ONLY, and I don't have the need or the time to get into fixing that, although I suspect it's an easy fix.  It does, however, allow for shift clicking up and down the current node.
  2.  You can shift click, then ctrl-click other items, but if you do a subsequent shift click, it gets weird again.  Once again, I don't have the need to fix this at the moment.

My subsequent post will cover copying and pasting an entire tree node.  It should be noted that this script and the following script can be used in conjunction (I am actually using both on the same page).

7 Answers, 1 is accepted

Sort by
0
Terry Hoiness
Top achievements
Rank 1
answered on 26 Oct 2010, 04:40 PM
Next we move on to client side copying and pasting of nodes and their children WITHOUT A POSTBACK.  Who doesn't like that?  It's lightweight and is nearly instantaneous.

<body>
<telerik:RadCodeBlock runat="server" ID="RadCodeBlock1">
   <script type="text/javascript">
                var treeView;
                var textBox;
                var nodeHolder;
 
                function pageLoad()
                {
                    treeView = $find ("<%= treeYourTree.ClientID %>");
                }
 
                //This function is where you copy your node and hold it.
                //...pretty straight forward
                function copyNode(args)
                {
                    if (treeView.get_selectedNodes!=null)
                    {
                        nodeHolder = treeView.get_selectedNodes();
                    }
                    return false;
                }
 
                //Pasting the node
                //Here's where the magic happens
                function pasteNode(args){
                    treeView.trackChanges();
                    if (treeView.get_selectedNodes != null)
                    {
                        //Get the current selected nodes
                        for (var x=0; x <treeView.get_selectedNodes().length; x++)
                        {
                            //Get the parent of the selected node
                            var parent = treeView.get_selectedNodes()[x];
                             
                            //Iterate through the nodes previously copied
                            for (var i=0; i<nodeHolder.length; i++)
                            {
                                if (nodeHolder[i] != null)
                                {
                                   //And Paste the node!
                                    parent.get_nodes().add(nodeCopy(nodeHolder[i]));
                                }
                            }
                        }
                        treeView.commitChanges();   
                    }
                     
                    return false;
                }
 
                //I lied... This is where the real magic happens.
                //This is a recursive function that copies from parent to children.
                //If you like, study this pattern, as I came up with this out of necessity (it's my pride and joy ;) ), and it comes in handy A LOT (I even adapt it for server side functions when iterating through a tree).
                function nodeCopy(selectNode)
                {
                    var nodeReturn = new Telerik.Web.UI.RadTreeNode();
                    nodeReturn.set_text(selectNode.get_text());
                    if (selectNode.get_nodes()!=null)
                    {
                        for (var i=0; i< selectNode.get_nodes().get_count(); i++)
                        {
                            var currentNode = selectNode.get_nodes().getNode(i);
                            nodeReturn.get_nodes().add(nodeCopy(currentNode));                           
                        }
                    }
                    return nodeReturn;
                }
   </script>
</telerik:RadCodeBlock>
 
        <!-- rad tree goes somewhere in here -->
        <asp:Button ID="btnCopy" OnClientClick="return copyNode()"
        Text="Copy Node(s)" runat="server" /><br />
        <asp:Button ID="btnPaste" CssClass="qsfButton" OnClientClick="return pasteNode()" Text="Paste Node(s)" runat="server" />
 
</body>

Features:
  1.  Will copy multiple selected rows with their children.
  2.  Will paste to multiple selected rows.

Known Limitations:
  1.  **The COPY function does not survive a partial postback or a full postback (meaning if you paste after a copy and then a postback, it doesn't work).  I have tried to rectify this using cookies, etc, but have not had luck to date.  The latter seems obvious, but the former (partial postback) is odd to me.  I really haven't had time to work through it, but if someone sees something obvious, let me know.

Work Around:
  1.  If you copy and paste prior to a partial post back, it will paste after the partial postback.  Once again, does anyone have any insight into this?

For Study:
  1.  Ok, I don't like to toot my own horn, but I find my iterative self-recursive function pretty sweet.  It made my brain hurt, but once I unlocked the pattern, I started finding several uses for it when dealing with recursive trees and data.  If you are interested, I pointed it out in the code above
 

Note: These are just thrown together, so I realize there may be some unknown deficiencies in the implementation.  Feel free to add and share whatever additional fixes you may implement, or problems you find...

**[edit]The problem with the partial postback is only when the tree gets refreshed.  I am using this where I have a drop down that changes the entire tree.  The copy function does not survive the rewriting of the tree.  I assume this is because once the tree is rewritten, the pointer to the original node is removed with the node (the node no longer exists), but this does not explain why a copy paste prior to the reloading of the tree survives the reload[/edit]
0
Nikolay Tsenkov
Telerik team
answered on 29 Oct 2010, 10:58 AM
Hello Terry Hoiness,

About the selection holding shift:
- It's already implemented and released in the Beta of Q3 2010 RadControls for ASP.NET AJAX, that we rolled out last week. Once you get the new assemblies you need only to enable the multiselection in RadTreeView and you will be able to use it.

About copying nodes on the client-side:
 - It's already implemented and again we released it with the latest Beta of our controls. It's called "clone" and is in the prototype of RadTreeNode client-side object representation. You also have control on whether to clone only the node or it's entire sub-tree.

Anyway, thank you for sharing your implementations of these features in our forum, we appreciate it! Your telerik points are updated!

Hope that you will like these and all the other new features that we included in this release!


Regards,
Nikolay Tsenkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Naisha
Top achievements
Rank 1
answered on 08 Nov 2010, 10:06 AM
Hi, 

Do you have an example of using "Clone"?
0
Nikolay Tsenkov
Telerik team
answered on 09 Nov 2010, 03:20 PM
Hello Itai,

Well here is an example:
1. Markup of the TreeView:
<telerik:RadTreeView runat="server" ID="RadTreeView1" OnClientLoad="onLoad">
</telerik:RadTreeView>
2. JavaScript:
function onLoad(sender) {
 
    var tree = sender;
 
    // create root node
    var rootNode = new Telerik.Web.UI.RadTreeNode();
    rootNode.set_text("RootNode");
 
    // create rootNode's children
    for (var i = 0; i < 10; i++) {
        var node = new Telerik.Web.UI.RadTreeNode();
        node.set_text("ChildNode");
        rootNode.get_nodes().add(node);
    }
 
    // create clone of rootNode
    var rootNodeClone = rootNode.clone();
 
    var shouldCloneChildren = true;
 
    // create clones of rootNode and all of its children
    var rootNodeCloneIncludingChildren = rootNode.clone(shouldCloneChildren);
 
    // add rootNode and its two clones
    tree.get_nodes().add(rootNode);
    tree.get_nodes().add(rootNodeClone);
    tree.get_nodes().add(rootNodeCloneIncludingChildren);
}

Hope you will like this new feature of RadTreeView (particularly RadTreeNode)!


Regards,
Nikolay Tsenkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Naisha
Top achievements
Rank 1
answered on 10 Nov 2010, 10:36 AM
Hello,

Great feature, indeed.
But now I have other issue.
I am cloning a node and its childes. Then, I am changing the value of the node:
NewNode.set_value(CountID); //in the client side

This is the error I am getting:

Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.
Details: Error parsing near '

<!DOCTYPE html P'.



Any idea?
0
Nikolay Tsenkov
Telerik team
answered on 15 Nov 2010, 01:11 PM
Hello Itai,

Well, you should probably post some code reproducing this problem because I was not able to reproduce it.

Here is what I have tried and wasn't able to reproduce with:
1. Markup:
<telerik:RadTreeView runat="server" ID="RadTreeView1" OnClientLoad="onLoad">
</telerik:RadTreeView>
<asp:Button runat="server" ID="Button1" OnClientClick="onButtonClick(); return false;"  />
2. JavaScript:
function onLoad(sender) {
 
    var tree = sender;
 
    // create root node
    var rootNode = new Telerik.Web.UI.RadTreeNode();
    rootNode.set_text("RootNode");
    rootNode.set_value("RootNode");
 
    // create rootNode's children
    for (var i = 0; i < 10; i++) {
        var node = new Telerik.Web.UI.RadTreeNode();
        node.set_text("ChildNode");
        node.set_value("ChildNode");
        rootNode.get_nodes().add(node);
    }
 
    // create clone of rootNode
    var rootNodeClone = rootNode.clone();
 
    var shouldCloneChildren = true;
 
    // create clones of rootNode and all of its children
    var rootNodeCloneIncludingChildren = rootNode.clone(shouldCloneChildren);
 
    // add rootNode and its two clones
    tree.get_nodes().add(rootNode);
    tree.get_nodes().add(rootNodeClone);
    tree.get_nodes().add(rootNodeCloneIncludingChildren);
}
 
function onButtonClick() {
    var tree = $find('<%= RadTreeView1.ClientID %>');
 
    var nodes = tree.get_allNodes();
 
    for (var i = 0; i < nodes.length; i++) {
        nodes[i].set_value(nodes[i].get_value() + "_changed!");
    }
}

After the page has loaded i have executed the following javascript in the console:
var tree = $find("RadTreeView1");
 
var nodes = tree.get_allNodes();
 
for (var i = 0; i < nodes.length; i++) {
    console.log(nodes[i].get_value());
}
and the values printed were:
RootNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
RootNode
RootNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
ChildNode
Then I have pressed the button under the TreeView (to change the values of all nodes) and again executed this javascript to log the values of the nodes. The result was
RootNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
RootNode_changed!
RootNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!
ChildNode_changed!

I hope that soon we will resolve the problem!


Regards,
Nikolay Tsenkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Naisha
Top achievements
Rank 1
answered on 15 Nov 2010, 01:18 PM
Hi,

I already posted the problem and the sulotion.
the problem is in node.set_value(x)
if x is an integer it cause a cannot convert from int to string error.
I solve it by adding '' to the value:
node.set_value(x+'')
Tags
TreeView
Asked by
Terry Hoiness
Top achievements
Rank 1
Answers by
Terry Hoiness
Top achievements
Rank 1
Nikolay Tsenkov
Telerik team
Naisha
Top achievements
Rank 1
Share this question
or