nshelms
nshelms

Reputation: 11

Making json conform to Bootstrap Treeview format

I'm trying to figure out the best way to transform some JSON data into the format requested for bootstrap-treeview. My initial thought was to create some sort of recursive function to go through and modify everything, but i'm having some real difficulty in achieving this. Any advice would be much appreciated!

Here a console log of the data returned by my service:

Object
  England: Object
    London: Object
      Bayerische Staatsbibliothek: Object
        Cod. arab. 1251: Array[1]
          0: Object
            key1: "adflkjadf",
            key2: "adflkjadfk",
            key3: "adlkfjadf",
            __proto__: Object
            length: 1
          text: "Cod. arab. 1251"
          __proto__: Array[0]
        Cod. arab. 1252: Array[1]
        Cod. arab. 1253: Array[1]
        Cod. arab. 1254: Array[1]
        Cod. arab. 1255: Array[1]
        Cod. arab. 1256: Array[1]
        Cod. arab. 1257: Array[1]
        Cod. arab. 1258: Array[1]
        Cod. arab. 1259: Array[1]
        Cod. arab. 1260: Array[1]
  Germany: Object
    Munich: Object
      Bayerische Staatsbibliothek: Object
        Cod. arab. 1251: Array[1]
          0: Object
            key1: "adflkjadf",
            key2: "adflkjadfk",
            key3: "adlkfjadf",
            __proto__: Object
            length: 1
          text: "Cod. arab. 1251"
          __proto__: Array[0]
        Cod. arab. 1252: Array[1]
        Cod. arab. 1253: Array[1]
        Cod. arab. 1254: Array[1]
        Cod. arab. 1255: Array[1]
        Cod. arab. 1256: Array[1]
        Cod. arab. 1257: Array[1]
        Cod. arab. 1258: Array[1]
        Cod. arab. 1259: Array[1]
        Cod. arab. 1260: Array[1]

Here's the format the the boostrap-treeview needs:

var tree = [
  {
    text: "Parent 1",
    nodes: [
      {
        text: "Child 1",
        nodes: [
          {
            text: "Grandchild 1"
          },
          {
            text: "Grandchild 2"
          }
        ]
      },
      {
        text: "Child 2"
      }
    ]
  },
  {
    text: "Parent 2"
  },
  {
    text: "Parent 3"
  },
  {
    text: "Parent 4"
  },
  {
    text: "Parent 5"
  }
];

Here's my attempt at a recursive function to accomplish this:

function format_for_treeview(node) {
  for (var key in node) {
    // skip loop if the property is from prototype
    if (!node.hasOwnProperty(key)) continue;

    if (typeof node === 'object') {
      format_for_treeview(node[key]);
      if (Array.isArray(node)) {
        node[key]['text'] = node[key]['bibliography_text'];
      } else {
        node[key]['text'] = key;
      }
    }
  }  
}

Upvotes: 1

Views: 3485

Answers (2)

anonymous
anonymous

Reputation: 4064

If you need bootstrap treeview and want parse an arbitrary JSON data to its format. You can use this recursive function. I just made a few changes on your original code.

function format_for_treeview(node) {
  for (var key in node) {
    // skip loop if the property is from prototype
    if (!node.hasOwnProperty(key)) continue;

    if (typeof node === 'object') {
      format_for_treeview(node[key]);
      if (Array.isArray(node)) {
        node[key]['text'] = node[key]['bibliography_text'];
      } else {
        node[key]['text'] = key;
      }
    }
  }  
}

Changing this will work like you expected. ( See the code snippet below. )

function format_for_treeview(data, arr) {
  for (var key in data) {
     if(Array.isArray(data[key]) || data[key].toString() === "[object Object]") {
        // when data[key] is an array or object
        var nodes = [];
        var completedNodes = completeNodes(data[key], nodes);
        arr.push({ text: key, nodes: completedNodes });
     } else {
        // when data[key] is just strings or integer values
        arr.push({ text: key + " : " + data[key] });
     }
  }  
  return arr;
}

var data = {
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string"
    },
    "lastName": {
      "type": "string"
    },
    "age": {
      "description": "Age in years",
      "type": "integer",
      "minimum": 0
    }
  },
  "required": ["firstName", "lastName"]
};

$(document).ready(function() {
  function format_for_treeview(data, arr) {
    for (var key in data) {
      if (Array.isArray(data[key]) || data[key].toString() === "[object Object]") {
        // when data[key] is an array or object
        var nodes = [];
        var completedNodes = format_for_treeview(data[key], nodes);
        arr.push({
          text: key,
          nodes: completedNodes
        });
      } else {
        // when data[key] is just strings or integer values
        arr.push({
          text: key + " : " + data[key]
        });
      }
    }
    return arr;
  }


  $("#my-treeview").treeview({
    color: "#428bca",
    expandIcon: "glyphicon glyphicon-stop",
    collapseIcon: "glyphicon glyphicon-unchecked",
    showTags: true,
    data: format_for_treeview(data, [])
  });

});
<link href="https://jonmiles.github.io/bootstrap-treeview/bower_components/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://jonmiles.github.io/bootstrap-treeview/js/bootstrap-treeview.js"></script>
<div id="my-treeview"></div>

You can customize the push part to make the " key : value " more noticable by inserting HTML string between them like this below.

arr.push({ text: "<span class="key-stub"> + key + "</span>", nodes: completedNodes });

Personally, if you just need a feature that converts JSON to a tree view, you don't have to struggle with this. Just consider using this one. No conversion is required.

Upvotes: 0

nshelms
nshelms

Reputation: 11

With help from the following link I discovered d3's nest() function does almost exactly what i needed. However, i did have to fork the d3.js file and rename the 'key' and 'values' key names in the nest()->entries() map function.

Additionally, I modified the service to return an array of objects instead of trying to do grouping inside the service.

  var withText = jsondata.map(function(i) {
    i['text'] = i['bibliography_text'];
    return i;
  });

  var nestedData = d3.nest()
    .key(function(d) { return d.country; })
    .key(function(d) { return d.city; })
    .entries(withText);

The resulting output gives me an array exactly like the var tree = [...] listed above.

Upvotes: 0

Related Questions