1

I am a complete javascript newbie, how can I integrate, jsTree on the front end, with the backend services in node.js. The backend is written using the Treemodel library (http://jnuno.com/tree-model-js/). With additional functions such as

function getChildren(x)
{
    var result=[];
    if(x.hasChildren())
    {
        for(i=0;i<x.children.length;i++)
        {
            result.push(x.children[i].model);
        }
    }
    return result;
}

and

function expandAll(node) {
    console.log(getChildren(node));
    for (var t = 0; t < node.children.length; t++) {
        if (node.children[t].hasChildren()) {
            expandAll(node.children[t]);
        }
    }
}

My data is in initially in flat-text form :

var items = [
    {'id': 2, 'parentid': 1, 'title': "Delhi"},
    {'id': 3, 'parentid': 2, 'title': "CP"},
    {'id': 4, 'parentid': 2, 'title': "Saket"},
    {'id': 1, 'parentid': 0, 'title': "India"},
    {'id': 5, 'parentid': 1, 'title': "Mumbai"},
    {'id': 6, 'parentid': 5, 'title': "Andheri"},
    {'id': 7, 'parentid': 5, 'title': "Worli"},
    {'id': 8, 'parentid': 7, 'title': "Wankhede"}
];

That has been converted to JSON by using the following code with underscore.js-

unflatten = function( array, parent, tree ){

    tree = typeof tree !== 'undefined' ? tree : [];
    parent = typeof parent !== 'undefined' ? parent : { id: 0 };

    var children = _.filter( array, function(child){ return child.parentid == parent.id; });

    if( !_.isEmpty( children )  ){
        if( parent.id == 0 ){
           tree = children;   
        }else{
           parent['children'] = children
        }
        _.each( children, function( child ){ unflatten( array, child ) } );                    
    }

    return tree;
}

items = unflatten(items); 

I will be implementing a tree structure in the front end with AJAX lazy loading, something very similar to: http://thejackalofjavascript.com/file-browser-with-jstree-angularjs-and-expressjs/

I just need help in understanding how the jsTree will be implemented with TreeModel, and how to make the lazy loading happen with the getChildren method implemented in the backend.

Thanks

1 Answers1

0

Here is a simple example using restify server.

1) Create a project folder with the following package.json file:

{
  "name": "remote-tree",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "flat-to-nested": "1.0.2",
    "restify": "4.3.0",
    "tree-model": "1.0.6"
  }
}

2) Run npm install.

3) Create a node script server.js with the following content

let restify = require('restify'),
  TreeModel = require('tree-model'),
  FlatToNested = require('flat-to-nested'),
  flatToNested = new FlatToNested({parent: 'parentid'}),
  tree = new TreeModel()

let items = [
  {id: 0},
  {id: 2, parentid: 1, title: 'Delhi'},
  {id: 3, parentid: 2, title: 'CP'},
  {id: 4, parentid: 2, title: 'Saket'},
  {id: 1, parentid: 0, title: 'India'},
  {id: 5, parentid: 1, title: 'Mumbai'},
  {id: 6, parentid: 5, title: 'Andheri'},
  {id: 7, parentid: 5, title: 'Worli'},
  {id: 8, parentid: 7, title: 'Wankhede'}]

let root = tree.parse(flatToNested.convert(items))

let server = restify.createServer()

server.get('/public', restify.serveStatic({
  directory: './public',
  default: 'index.html',
  file: 'index.html'
}))

server.get('/children/:id', (req, res, next) => {
  let id = req.params.id
  let node = root.first(node => node.model.id == id)
  if (node && node.hasChildren()) {
    res.send(200, node.children.map(child => ({
      id: child.model.id,
      text: child.model.title,
      children: child.hasChildren()
    })))
  } else {
    res.send(404)
  }

  return next()
})

server.listen(8080)

4) Create a public folder to place your index.html file

5) Create the index.html file inside public folder with the following content:

<!DOCTYPE html>
<html>
<head>
  <title>remote-tree</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
</head>
<body>
  <div id="jstree"></div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
  <script>
    $(() => $('#jstree').jstree({
      core: {
        data: (node, cb) => {
          let id = node.id === '#' ? 0 : node.id;
          fetch(`/children/${id}`).then(response => response.json()).then(children => cb(children))
        }
      }
    }))
  </script>
</body>
</html>

6) Run npm start and browse to localhost:8080/public

jnuno
  • 711
  • 5
  • 8
  • Thanks for the amazing quick response! Was just wondering whether there is any particular reason for using restify instead of express, because I'll be using the express generator to get the general project structure. Also, does this mean I don't need to use the getChildren/ expandAll method that I wrote (I only wrote that because there wasn't one in Treemodel), and jsTree will handle that? PS: I love treemodel. – howyoulikemenow Jan 05 '17 at 10:41
  • @howyoulikemenow You can use express as well, I don't know restify nor express, it was just a quick way to have a rest resource and serve an index.html. Supporting an expandAll feature will need more code. – jnuno Jan 05 '17 at 13:47
  • I know this is a little off-topic but is there a need for an expandAll feature in node.js, won't jsTree with methods like be able to handle that? – howyoulikemenow Jan 09 '17 at 09:15
  • @howyoulikemenow it should work without expandAll in node but it will lead to more requests than a custom endpoint. It depends on the tree depth. – jnuno Jan 09 '17 at 13:41