This was a fun project that came about because of a lack of foresight in the design process. I had argued with the Business Analyst that this project would take a substantial amount of time to complete, and that it may be easier to have a simpler control, such as 2 list controls, or one list that contains the initial groups, and one or more with the child objects, which in my case was substations and generating units. But, the B.A. pushed back and insisted on having 2 identical tree controls with multiple levels of Child objects, (of course shown by a different icon for each). I did research to find out exactly what kind of control I could simply reuse, as I thought there had to be an implementation of drag and drop between 2 tree controls! But, of course there wasn’t. It’s trivial to implement drag and drop between 2 tree controls, but only with the exact same objects between the 2. If you wanted to have more than one ‘level’, there was no such control that existed anywhere, at least at that time (a few years ago now). Also, we were restricted to only using free controls, such as Jquery plugins, and such. Other commercial products also didn’t implement what I wanted, such as Telerik or Infragistics. So, I decided on jstree (www.jstree.com), which looked great at least. But, of course, there was no support, and not a lot of developers were using it. But, it did have events that detected drag and drop between different instances of jstree, which at least was a good starting point. By the way, the advice I got from other ‘developers’ on our team was that this little project was quite impossible, and to just give up and implement it in a trivial matter, using lists. But, I was determined so I forged ahead, and got to work with jstree.
My solution used recursion, which seemed like the easiest way to accomplish what I needed. As, if you actually think about this, before starting work on it, (sadly not a lot of developers actually think about design, and logic before coding these days), you need to implement logic to prevent drag and drop of nodes on a different ‘level’ of the current object that you are moving. And, then of course, you would have to delete all the dragged objects from the source tree, and from the database (in certain cases anyways), so it’s quite involved to implement all of this correctly, and to have it done in a few weeks which was my time that I estimated! The final solution was also much more involved than this demo, as it included more objects to ‘wrap’ around the basic solution, including ‘maps’, which would allow the user to custom make maps, with geographic locations, as a starting point for creating a destination tree ‘map’. And, other engineering terminology, which I won’t go into detail on here. A project like this is a good way to determine how a developer works. Any real developer would push back on a Business Analyst’s flawed logic, and incomplete design, especially in this case. And, at the very least, understand how it would affect your existing project, and whether it makes sense to incorporate something like this into the existing system, or not. So, something like this project would be a good way to weed out poor developers from good ones. A good developer can actually produce a great looking and functioning UI for the user. If they can’t, you should reconsider what their contribution to the project actually means. It’s very easy to just be good at one portion of the ‘stack’ such as web services, or database development, but it’s many, many times harder to actually create an entire project from scratch, and have an incredibly complex UI system working perfectly. As, if you think about it, you would realize that every level such as the database project, web services project, and of course the UI project would have to work perfectly in order to be useful to the user. So, if you are hiring a new developer, this could be the perfect project to give them in the first few weeks, as the few hours you spent interviewing them, doesn’t really determine if they are a competent developer when working on a real world problem.
Now back to the jstree solution: To get this running, the basic HTML for the placement of the controls is as follows:
You can just place a div wherever you want a tree control to appear on your form. So for side by side controls, wrap 2 divs within another div. A basic implementation of Jstree is as follows:
This creates the actual tree in the divGroupingsTree div. Then loads all the nodes that you want to display from the url (“/Services/CutPlaneManagement.asmx/GetAllElectricalGroupsSubstations?…) The next step is to bind whatever events that you need for each tree. In my case, it’s the move_node.jstree event, which fires whenever a user moves a node to a new location either on a different tree or the same tree. This code fires when the tree detects a node that has been moved:
This also creates a list, and ensures that all items are moved to the appropriate parent at the destination tree. The next portion of the code to examine is the call to ‘updatesubstations’ which actually updates the child nodes in the database itself. This code is taken from the ‘added groups’ tree creation code:
The web service call basically updates the child list per map, as we are using a map id to group each ‘mapping’ of child objects:
The next part of the code recreates the hierarchy and returns the tree object to jstree:
Jstree then uses this hierarchy to automatically recreate the parent child hierarchy as reflected by the latest actions of the user:
The actual function that recursively moves nodes is moveNodes(), which is rather long, and complicated:
This function basically tests for the amount of parent objects to move, so if it’s greater than 1, then it will eventually recursively call itself, to accomplish the moving of multiple parent/child levels below the selected node that the user actually moved. Now, the last part I wanted to show you was the createSubstationList() recursive call, which builds the list of current substations (child objects) that are in the tree after the move was completed. This, list is then used by the ‘UpdateSubstations()’ server side call to actually update the list of substations in the Database itself:
This is a fairly straightforward recursive function that basically searches for any children within the parent node, and recursively traverses the html tree to retrieve all substations (our child object name in this case), and add to the substlist parameter.
Here is the actual demo project running. In this case, I demonstrate before and after screenshots of moving nodes from within the available ‘map’ to the destination or ‘added’ map. The first is to move a parent folder (Group) along with all child node(s) to the main root folder, and see if it will be smart enough to create all parent groups in the destination, along with the newly moved groups and ‘substation’ child nodes(s) of course! So, I will drag the ‘Edm – Edmonds’ folder from the Available to Added tree and drop it inside the ‘B.C. – British Columbia’ folder, and see what happens:
Dragged to Destination tree:
I simply clicked on the ‘Edm – Edmonds’ folder and dragged it to just under the B.C. folder and dropped it there. You can drop it anywhere that it makes sense, such as under the ‘GVRD – Lower Mainland’ folder as well.
Yay!, it worked! You can see that it was smart enough to create both the ‘Bby – Burnaby’ folder, then the ‘Edm – Edmonds’ folder, and place the newly moved child node in the ‘Edm – Edmonds’ folder, which is exactly what we wanted, (or at least what our engineers wanted in this case.). So, it should work in a similar fashion if you drag a child node, lets say ‘East Van 1 – East Vancouver Substation 1’ from right to left, and drop it in the B.C. root folder:
While Dragging from right to left:
So, in this case, the ‘East Van – East Vancouver’ folder existed in both trees, with one unique child node in each folder. I dragged from right to left, and it successfully placed the ‘East Van 1 – East Vancouver Substation 1’ child node in the destination folder, and then deleted the source folder, as there was no reason for it to exist any longer. Of course, you can also drag whatever folder or node you want back and forth, and it should successfully create and delete parent folders accordingly, and in a way that makes sense.
I hope you have found this project useful, and can use this in one of your future projects, or can at least appreciate the complexity of the problem, and ultimate solution. I have also included the complete source code, that you can download and re-use if you like.Source code CodeProject Demo HERE