I need help with with displaying JSON data on a page like expandable/collapsible list.
Here is a valid JSON I`ve made converting from XML with Python:
JSON Data
And to display it I`m usig this:
<!DOCTYPE HTML>
<head>
<title>JSON Tree View</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js" type="text/javascript"></script>
</head>
<script>
function json_tree(object){
var json="<ul>";
for(prop in object){
var value = object[prop];
switch (typeof(value)){
case "object":
var token = Math.random().toString(36).substr(2,16);
json += "<li><a class='label' href='#"+token+"' data-toggle='collapse'>"+prop+"="+value+"</a><div id='"+token+"' class='collapse'>"+json_tree(value)+"</div></li>";
break;
default:
json += "<li>"+prop+"="+value+"</li>";
}
}
return json+"</ul>";
}
</script>
<body style="margin: 40px;">
<h3>Paste JSON Into The Textarea Below and Click 'Build Tree'</h3>
<textarea id="json" style="width: 100%;min-height:300px;">
</textarea>
<button onclick="$('#output').html(json_tree(JSON.parse($('#json').val())));">Build Tree</button>
<div id="output">
</div>
</body>
</html>
This is what I get:
Image
I need help "filltering" (or merge with upper node) those "0" and "1", and also - how to show only values of the attributes without the names (or if do you have some better idea how can I dusplay this list)?
Cross-platform to open JSON files: Generally, users can open the JSON file in any text editor as it is a plain text-based file. The Google Chrome and Mozilla Firefox web browsers are cross-platform to open JSON files that are compatible with every operating system (OS).
Some of the links to the questions are no longer accessible. I assume you are looking for how to make a collapsible JSON view.
you can jump to Full code.
the code is very short (200 linesβ, including JSDoc, comment, test code.)
This question in some skill is very much like how to make the table of contents. (TOC)
First of all, JSON data is like an object. All we need to do is to add some more attributes (key, depth, children, ...) for each item.
Once these actions are done, all left is to render, and here is the pseudo-code for rendering.
render(node) {
const divFlag = document.createRange().createContextualFragment(`<div style="margin-left:${node.depth * 18}px"></div>`)
const divElem = divFlag.querySelector("div")
const spanFlag = document.createRange().createContextualFragment(
`<span class="ms-2">${node.key} : ${node.value}</span>`
)
node.children.forEach(subNode => {
const subElem = render(subNode)
spanFlag.append(subElem)
})
divElem.append(spanFlag)
return divElem
}
both CSS is not necessary.
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossOrigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"
integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ=="
crossOrigin="anonymous" referrerpolicy="no-referrer"/>
<script type="module">
// π main script {Node, Tree, JsonView}
class Node {
/**
* @description Add more attributes to the item.
* @param {*} item
* @param {*} key
* @param {Node} parent
* */
constructor(item, key, parent) {
this.key = key
/** @param {string} */
this.type = Array.isArray(item) ? "array" : typeof item
/** @param {Number} */
this.depth = parent ? parent.depth + 1 : 0
this.value = item
this.parent = parent
/** @param {[Node]} */
this.children = []
}
}
class Tree {
/**
* @description Given the root node, it will complete the children of it.
* @param {Node} rootNode
*/
constructor(rootNode) {
this.root = rootNode
const obj = this.root.value
if (!(obj instanceof Object)) { // Array is an Object too.
return
}
Object.keys(obj).forEach(keyOrIdx => {
const value = obj[keyOrIdx]
const subNode = new Node(value, keyOrIdx, rootNode)
const subTree = new Tree(subNode)
rootNode.children.push(subTree.root)
})
}
/**
* @param {string | Object} jsonData
* @return {Tree}
*/
static CreateTree(jsonData) {
jsonData = typeof jsonData === "string" ? JSON.parse(jsonData) : jsonData
const rootNode = new Node(jsonData, "root", null)
return new Tree(rootNode)
}
}
class JsonView {
static DefaultColorMap = {
text: {
string: "green",
number: "#f9ae58",
boolean: "#ca4ff8",
array: "black",
object: "black",
},
bg: {
object: "none"
// ... You can add more by yourself. They are like the text as above.
}
}
static NewConfig() {
return JSON.parse(JSON.stringify(JsonView.DefaultColorMap))
}
static SEPARATOR = " : "
/** @type {Tree} */
#tree
/**
* @param {Tree} tree
* */
constructor(tree) {
this.#tree = tree
}
/**
* @param {Node} node
* @param {Object} colorMap
*/
#render(node, colorMap = JsonView.DefaultColorMap) {
/**
* @param {Node} node
* */
const getValue = (node) => {
const typeName = node.type
switch (typeName) {
case "object":
return `object {${Object.keys(node.value).length}}`
case "array":
return `array [${Object.keys(node.value).length}]`
default:
return node.value
}
}
const arrowIcon = ["object", "array"].includes(node.type) ? `<i class="fas fa-caret-down"></i>` : ""
const divFlag = document.createRange().createContextualFragment(`<div style="margin-left:${node.depth * 18}px">${arrowIcon}</div>`)
const divElem = divFlag.querySelector("div")
const textColor = colorMap.text[node.type] !== undefined ? `color:${colorMap.text[node.type]}` : ""
const bgColor = colorMap.bg[node.type] !== undefined ? `background-color:${colorMap.bg[node.type]}` : ""
const valueStyle = (textColor + bgColor).length > 0 ? `style=${[textColor, bgColor].join(";")}` : ""
const keyName = node.depth !== 0 ? node.key + JsonView.SEPARATOR : "" // depth = 0 its key is "root" which is created by the system, so ignore it.
const spanFlag = document.createRange().createContextualFragment(
`<span class="ms-2">${keyName}<span ${valueStyle}>${getValue(node)}</span></span>`
)
const isCollapsible = ["object", "array"].includes(node.type)
node.children.forEach(subNode => {
const subElem = this.#render(subNode, colorMap)
if (isCollapsible) {
divFlag.querySelector(`i`).addEventListener("click", (e) => {
e.stopPropagation()
subElem.dataset.toggle = subElem.dataset.toggle === undefined ? "none" :
subElem.dataset.toggle === "none" ? "" : "none"
e.target.className = subElem.dataset.toggle === "none" ? "fas fa-caret-right" : "fas fa-caret-down" // Change the icon to β or β
subElem.querySelectorAll(`*`).forEach(e => e.style.display = subElem.dataset.toggle)
})
}
spanFlag.append(subElem)
})
divElem.append(spanFlag)
return divElem
}
/**
* @param {Element} targetElem
* @param {?Object} colorMap
*/
render(targetElem, colorMap = JsonView.DefaultColorMap) {
targetElem.append(this.#render(this.#tree.root, colorMap))
}
}
// π Below is Test
function main(outputElem) {
const testObj = {
db: {
port: 1234,
name: "My db",
tables: [
{id: 1, name: "table 1"},
{id: 2, name: "table 2"},
],
},
options: {
debug: false,
ui: true,
},
person: [
"Foo",
"Bar"
]
}
const tree = Tree.CreateTree(testObj)
const jsonView = new JsonView(tree)
jsonView.render(outputElem)
/* If you want to set the color by yourself, you can try as below
const config = JsonView.NewConfig()
config.bg.object = "red"
jsonView.render(outputElem, config)
*/
}
(() => {
window.onload = () => {
main(document.body)
}
})()
</script>
vanilla JavaScript
pgrabovets' json-view
is amazingly clean and well designed.
Check out the demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With