JSON Tree Viewer in WebViewer (Without Extensions)

Hi everyone :partying_face:

Super update!!!

I couldn’t accept having compromises, so here’s the updated and complete guide with ALL THE FEATURES! Images, links, buttons, functions, keyRenderer, highlight, themes, and much more..

JSON of the image above
{
	"avatar": "https://i.imgur.com/1bX5QH6.jpg",
	"string": "Lorem ipsum dolor sit amet",
	"integer": 42,
	"url": "new URL('https://example.com')",
	"float": 114.514,
	"error": "error message",
	"warning": "WARNING!",
	"bigint": "123456789087654321n",
	"undefined": "undefined",
	"timer": 1,
	"date": "new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)')",
	"link": "http://example.com",
	"emptyArray": [],
	"array": [
		31,
		19,
		810,
		"test",
		"NaN"
	],
	"emptyObject": [],
	"object": {
		"bar": false,
		"foo": true,
		"last": "null"
	},
	"emptyMap": "new Map()",
	"map": "(() => { const m = new Map(); m.set('foo', 1); m.set('goo', 'hello'); m.set({}, 'world'); return m; })()",
	"emptySet": "new Set()",
	"set": "new Set([1, 2, 3])",
	"loopObject": "(() => { const obj = { foo: 42, goo: 'Lorem Ipsum' }; obj.self = obj; return obj; })()",
	"loopArray": "(() => { const obj = { foo: 42, goo: 'Lorem Ipsum' }; obj.self = obj; const arr = [obj]; arr[1] = arr; return arr; })()",
	"longArray": "Array.from({ length: 1000 }).map((_, i) => i)",
	"nestedArray": {
		"1": 2,
		"3": 4
	},
	"superLongString": "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
	"function": "function aPlusB (a, b) { return a + b }",
	"constFunction": "(function(a, b) { return a + b })",
	"anonymousFunction": "(function (a, b) { return a + b })",
	"shortFunction": "((arg1, arg2) => console.log(arg1, arg2))",
	"shortLongFunction": "((arg1, arg2) => { console.log(arg1, arg2); return '123' })",
	"string_number": "1234"
}

:bookmark: Index

1. Setup the WebView

2. renderJsonTree (main function)

3. Themes

4. Highlight Updates

5. KeyRenderer

6. Offline viewer

7. Json Viewer dialog

8. AIA

9. Credits


Setup the WebView

The first thing we do is import the HTML into the assets and set the WebViewer’s homeUrl to http://localhost/ + file_name.html, in this case:

http://localhost/json-viewer.html


renderJsonTree

The only function we’ll use is WebViewer.EvaluateJS, which will call renderJsonTree from the HTML file and therefore create the structure in our WebViewer.

The dictionary we pass will contain the props, as they’re called in the documentation, which are the viewer’s settings.

The most important prop will be value, which will contain our JSON/dictionary.

Below is the full props list taken directly from the official documentation.

Props
Name Type Default Description
value any - Your input data. Any value, object, Array, primitive type, even Map or Set.
rootName string or false “root” The name of the root value.
theme "light"
| "dark"
| "auto"
| Base16
"light" Color theme.
className string - Custom class name.
style CSSProperties - Custom style.
sx SxProps - The sx prop lets you style elements inline, using values from the theme.
indentWidth number 3 Indent width for nested objects
keyRenderer {when: (props) => boolean} - Customize the rendering of key when keyRenderer.when returns true. Render null in keyRenderer will cause the colons to be hidden.
valueTypes ValueTypes - Customize the definition of data types. See Defining Data Types
enableAdd boolean |
(path, currentValue) => boolean
false Whether enable add feature. Provide a function to customize this behavior by returning a boolean based on the value and path.
enableDelete boolean |
(path, currentValue) => boolean
false Whether enable delete feature. Provide a function to customize this behavior by returning a boolean based on the value and path.
enableClipboard boolean false Whether enable clipboard feature.
editable boolean |
(path, currentValue) => boolean
false Whether enable edit feature. Provide a function to customize this behavior by returning a boolean based on the value and path.
onChange (path, oldVal, newVal) => void - Callback when value changed.
onCopy (path, value) => void - Callback when value copied, you can use it to customize the copy behavior.
*Note: you will have to write the data to the clipboard by yourself.
onSelect (path, value) => void - Callback when value selected.
onAdd (path) => void - Callback when the add button is clicked. This is the function which implements the add feature. Please see the DEMO for more details.
onDelete (path) => void - Callback when the delete button is clicked. This is the function which implements the delete feature. Please see the DEMO for more details.
defaultInspectDepth number 5 Default inspect depth for nested objects.

* If the number is set too large, it could result in performance issues.
defaultInspectControl (path, currentValue) => boolean - Whether expand or collapse a field by default. Using this will override defaultInspectDepth.
maxDisplayLength number 30 Hide items after reaching the count.
Array and Object will be affected.

* If the number is set too large, it could result in performance issues.
groupArraysAfterLength number 100 Group arrays after reaching the count.
Groups are displayed with bracket notation and can be expanded and collapsed by clicking on the brackets.
collapseStringsAfterLength number 50 Cut off the string after reaching the count. Collapsed strings are followed by an ellipsis.

String content can be expanded and collapsed by clicking on the string value.
objectSortKeys boolean false Whether sort keys through String.prototype.localeCompare()
quotesOnKeys boolean true Whether add quotes on keys.
displayDataTypes boolean true Whether display data type labels.
displaySize boolean |
(path, currentValue) => boolean
true Whether display the size of Object, Array, Map and Set. Provide a function to customize this behavior by returning a boolean based on the value and path.
displayComma boolean true Whether display commas at the end of the line.
highlightUpdates boolean true Whether to highlight updates.
How onChange, onCopy, onSelect, onAdd and onDelete works?

Unlike the other props that receive strings, numbers, and booleans, these ones receive a function that allows communication with Kodular through WebViewStringChange.

Each of these props needs to be enabled with another prop, below the association.

onChange >> editable
onCopy >> enableClipboard
onSelect >> not necessary
onAdd >> enableAdd
onDelete >> enableDelete

I’ll explain only onChange since they all work the same way but with different functions.

We will assign this function as the value for the onChange key.

(path, oldVal, newVal) => window.Kodular.setWebViewString(JSON.stringify({action: ‘onChange’, path: path, oldVal: oldVal, newVal: newVal}))

This will trigger the WebView.WebViewStringChange event, passing a json containing something like:

{
	"action": "onChange",
	"path": "path of the change",
	"oldVal": "old value",
	"newVal": "new value"
}

So, every time a value in the tree is modified by the user, WebViewStringChange will be triggered, giving us a way to understand how the user interacted with the WebView/structure.

WebView.WebViewStringChange

Here all the available props as a dictionary


Themes

This magnificent script also allows us to use Base16 themes, and to use them we simply need to pass a dictionary wrapped in () into the theme prop.

In the project at the end of the guide, in the themes variable, you will find some themes I found online.


Nothing stops you from creating your own custom one!


Highlight Updates


This feature has been my nemesis throughout the entire project, and I’m glad to say that now you just need to enable highlightUpdates in the props and you’re done! :partying_face:


KeyRenderer

image
In addition to the classic struck-through float enabled by the value 114.514, I experimented and managed to achieve different effects, for example,
if value contains the word “error” it underlines and colors the key in red

This is possible thanks to a function in the html that provides the correct formatting based on certain conditions.

To enable the keyRenderer, you just need to pass a pair in the prop dictionary.
blocks(49)

For explanations about the HTML file, I’ll wait for questions to avoid making the guide too heavy


Offline viewer

To obtain the viewer offline, It was enough to simply download the libraries and adapt the HTML code, for you it will be a bit easier :grin: just import all the files

json-viewer-offline.html
react-min.js
react-dom-min.js
json-viewer-mod.js

into the asset

For explanations about the HTML file, I’ll wait for questions to avoid making the guide too heavy


Json Viewer dialog


I think it’s fairly self-explanatory


AIA

json_viewer.aia (15.7 KB)

json-viewer.html (5.1 KB)

json_viewer_offline.aia (108.8 KB)

json-viewer-offline.html (4.8 KB)
offline json-viewer files.zip (91.9 KB)

Essential project

everything you need to make it all work…



image


Credits

2 Likes