jqueryangularjsnode.jsjstreetreemodel

Integrating jsTree with Treemodel


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


Solution

  • 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