javascriptunderscore.jstreelist

How does one dynamically build a treelist using pure Javascript or a library like underscore?


I'm having trouble getting the output from the following json

`[
 {theLevel:1,displayName: "John Doe1", index:1, parIndex:null },
 {theLevel:1,displayName: "John Doe2", index:2, parIndex:null },
 {theLevel:2,displayName: "John Doe3", index:3, parIndex:1 },
 {theLevel:2,displayName: "John Doe4", index:4, parIndex:1 },
 {theLevel:3,displayName: "John Doe5", index:5, parIndex:2 },
 {theLevel:3,displayName: "John Doe6", index:6, parIndex:2 },
]`

My expected output is as follows:

  [
      {text:"John Doe1", items:[{text:"John Doe3"},{text:"John Doe4"} ]},
      {text: "John Doe2, items:[{text:"John Doe5"},{text:"John Doe6"}]} ]

Solution

  • Here's one solution which does a few iterations of the whole data to produce a tree. Some of these iterations can be combined to improve performance but here I've left them as they are so that it's clearer what's going on:

    1. Add a children property to each person

      _.each(data, function(person){
          _.extend(person, {children: []});
      });
      
    2. Create a hash of the data with the index of the person as the key and the person as the value

      var people = _.reduce(data, function(memo, person){
          memo[person.index] = person
          return memo;
      }, {} ); 
      

      The people object will look like so:

      {
         1: {theLevel:1,displayName: "John Doe1", index:1, parIndex:null },
         2: {theLevel:1,displayName: "John Doe2", index:2, parIndex:null },
         3: {theLevel:2,displayName: "John Doe3", index:3, parIndex:1 }
         etc.
      }
      
    3. Add each child to the children of it's parent:

      _.each(data, function(person){
          if( !_.isNull(person.parIndex)) people[person.parIndex].children.push(person);
      });
      

      This will leave you with a tree.

    4. You can then transform this tree into whatever you like. This snippet will produce the output in the question:

      function isParent (person) {
          return !_.isEmpty(person.children);
      }
      
      var parents = _.filter(people, isParent);
      
      var result = _.map(parents, function(person){
          return {
              text: person.displayName,
              items: _.map(person.children, function(child){
                  return { text: child.displayName };
              })
          };