Introduction
I’ve seen several good tutorials on the net about jsTree and MVC, but they’re all somehow outdated and don’t work with jsTree’s latest version (which is a free component). It’s been a long time since I wanted to post the experience I had using jsTree (for those who don’t know what jsTree is, please go here: www.jstree.com). And what’s better to get it working than making a simple “File Manager”?
In this article, I will focus on two aspects of jsTree. The first that really blew me out was the possibility of moving trees by drag and drop, like in Windows Explorer (see Picture 1). The other feature I won’t cover (but is in the code) is using the right mouse button to display a context menu and from there create directories, rename, etc. I will not post a complete solution with rename, cut & copy features in this article, because it is just intended to be a starting point on how to use jQuery and MVC.
Picture 1: Drag and Drop
Using the code
First, we have to define our trees as JSON classes with a particular format:
public class JsTreeModel
{
public string data;
public JsTreeAttribute attr;
public string state = "open";
public List<JsTreeModel> children;
}
public class JsTreeAttribute
{
public string id;
}
So in the data attribute, we’ll store the tree’s title, and the complete path will be stored in the ID attribute. The state of the tree will have all child leaves expanded by default, that’s what “open” is for.
We will use recursion to populate our tree, nothing really complicated.
Binding the tree
We have to use the following JavaScript to bind the tree using jQuery:
$('#MainTree').jstree({
"json_data": {
"ajax": {
"url": "/Home/GetTreeData",
"type": "POST",
"dataType": "json",
"contentType": "application/json charset=utf-8"
}
},
"themes": {
"theme": "default",
"dots": false,
"icons": true,
"url": "/content/themes/default/style.css"
},
"plugins": ["themes", "json_data", "dnd", "contextmenu", "ui", "crrm"]
});
As you may have already understood, the “dnd
” plugin stands for “Drag and Drop”.
And then the following syntax to perform the drag and drop operations:
$('#MainTree').bind("move_node.jstree", function (e, data) {
data.rslt.o.each(function (i) {
$.ajax({
async: false,
type: 'POST',
url: "/Home/MoveData",
data: {
"path": $(this).attr("id"),
"destination": data.rslt.np.attr("id")
},
success: function (r) {
Refresh();
}
});
});
});
On the controller side, we have to use:
[HttpPost]
public ActionResult MoveData(string path, string destination)
{
FileAttributes attPath = System.IO.File.GetAttributes(path);
FileAttributes attDestination = System.IO.File.GetAttributes(path);
FileInfo fi = new FileInfo(path);
if ((attPath & FileAttributes.Directory) == FileAttributes.Directory)
{
if((attDestination & FileAttributes.Directory)==FileAttributes.Directory)
{
MoveDirectory(path, destination);
}
}
else
{
System.IO.File.Move(path, destination + "\\" + fi.Name);
}
AlreadyPopulated = false;
return null;
}
I had to find another way to move a directory because Microsoft’s “Directory.Move
” does not work in every case. Again, it’s just a starting point, it is not intended to be a complete solution.
Points of interest
One point that annoyed be a bit was the fact of having to refresh my tree in every task (move, create directory). It’s the only way I’ve found to keep sync the disk’s tree and the displayed one. Maybe some MVP could help me out if I just store the leaf’s name, I don’t know. I had to use a session state variable because otherwise if I click on the last leaf of the tree, I will have the entire tree populated again. And I couldn’t avoid it.
Anyway, I hope this article will help MVC developers wanting to use JSTree to improve the user’s experience and who don’t want to invest $500 in a professional component.