Overview

json2html is a pure javascript HTML templating library used to render JSON objects into HTML and can be used with

  • Native Javascript using the core library
  • jQuery as jquery plug-in with jquery events
  • Node.js as node.js package

Each wrapper uses the same template, allowing for the same template to be run on the browser or server!

Usage

JSON2HTML can be used on both the browser and the server.

Native & Node.js

Using the following on the browser or with Node.js

json2html.render(obj, template [,options])
  • obj object (or array) to render
  • template json2html template
  • [options] object with the following options
    • components object with name component pairs
  • output: HTML string
let html = json2html.render([{'s':'json2html'},{'s':'is'},{'s':'awesome'}],{'<>':'li','text':'${s}'});
jQuery

Use with jQuery to attach the result to a DOM object along with DOM events

$(selector).json2html(obj, template [,options])
  • obj object (or array) to render
  • template json2html template
  • [options] object with the following options
    • components object with name component pairs
    • data data object to be passed to jquery events (see Events)
    • method [append/prepend/replace] specify how elements will be added to the DOM
$('ul').json2html([{'s':'json2html'},{'s':'is'},{'s':'awesome'}],{'<>':'li','text':'${s}'});

Use to sub render components within a html attribute function call. Allows for jQuery events to be passed correctly.

$.json2html(obj, template [,options])
  • obj object (or array) to render
  • template json2html template
  • [options] object with the following options
    • components object with name component pairs
    • data data object to be passed to jquery events (see Events)
    • output [ihtml/html] specifies the output type
  • output: iHTML object (html with events) or HTML string (see output option)
Note: only use this when embedding within a 'html' attribute function call, use json2html.render instead if you want to render to a raw html string
    {'<>':'div','html':function(){
        return( $.json2html([{'s':'json2html'},{'s':'is'},{'s':'awesome'},{'<>':'li','html':'${s}'}) );
    }}

Template Types

Templates are a specified using json and can can be either an single object or an array of objects. Templates can be split into three different types: dom, block or component.

dom template

Use a dom template when you want to render a dom element (see dom template for more info)

{'<>':'span','html':'im an html element'};
<span>im an html element!</span>
block template

Use a block template when you want to render raw html/text or group a bunch of other templates together (see block template for more info)

{'html':'im raw <i>html</i>'};
im raw <i>html</i>
{'html':[
    {'html':'hi there!'},
    {'<>':'span','html':'im html'}
]};
hi there!
<span>im html</span>
component

Use a component when you want to create re-usable components. You can think of them as re-usable blocks (see component for more info)

    
json2html.component.add('link',{'<>':'a','href':'www.example.org','text':'click me'});

let template = {'[]':'link'};
<a href='www.example.org'>click me</a>

DOM Template

DOM templates are JSON objects that specify a hierarchy of DOM elements (div, span, li, etc..) with name value pairs of the attributes found on the DOM HTML element, with the exception the following reserved attribute names

  • <> specifies the type of DOM element (div, span etc..)
  • obj specifies the obj that this template should render
  • text specifies the text to use as the innerHTML
  • html specifies the innerHTML for this dom element or contains child templates
  • children (deprecated)
  • tag (deprecated)
let template = {'<>':'li','html':[
                    {'<>':'span','html':'${name} (${age})'}
                ]};
    
let data = [
    {'name':'Bob','age':40},
    {'name':'Frank','age':15},
    {'name':'Bill','age':65},
    {'name':'Robert','age':24}
];
    
$('ul').json2html(data,template);
<ul id="list">
    <li>
        <span>Bob (40)</span>
    </li>
    <li>
        <span>Frank (15)</span>
    </li>
    <li>
        <span>Bill (65)</span>
    </li>
    <li>
        <span>Robert (24)</span>
    </li>
</ul>
<> attribute

The first required step in creating a dom template is specifying the '<>' attribute for each object within the template. This will specify the HTML element (eg: div,a,p,table etc..) that you wish to be created. Note that the 'tag' attribute can also be used in support of legacy templates

{'<>':'div'}
<div></div>
text attribute

The reserved text attribute is used to specify the inner text of the DOM element. As with any other attribute you can specify a literal string, use short hand notation or an inline function (see Assignment for more details). It's recommended to use this to help prevent against XSS attacks

let data = [
    {"text":"<read this as text>"},
    {"text":"><img onerror='alert(0);'>"}
];

let template = {'<>':'div','text':'${text}'};
<div>&lt;read this as text&gt;</div>
<div>&gt;&lt;img onerror='alert(0);&gt;</div>

Use of an inline function can be used as well with the parameters (obj,index) and the 'this' mapped to obj.

let data = [
    {"text":"<span>read this as text</span>"}
];

let template = {'<>':'div','text':function(){ return(json2html.toText(this.text); }};
    <div>&lt;span&gt;read this as text&lt;/span&gt;</div>
html attribute

The reserved html attribute is used to specify the inner html of the DOM element. As with any other attribute you can specify a literal string, use short hand notation or an inline function (see Assignment for more details). In addition you can also specify an array of child templates that will belong to this DOM element.

It's highly recommended to use 'text' unless you're needing to specify html directly to help prevent against XSS injection attacks.

{'<>':'div','html':[
    {'<>':'span','html':'1'},
    {'<>':'span','html':'2'}
]} 
<div>
    <span>1</span>
    <span>2</span>
</div> 

Note that there are no limits to the number of children that a template may have or the number of nested levels of children.

{'<>':'div','html':[
    {'<>':'div','html':[
        {'<>':'span','html':'final'}
    ]
]} 
<div>
    <div>
        <span>final</span>
    </div>
</div>

Use of an inline function can be used to return and html string or from another json2html call. This may include inserting html using another core json2html.render call (or jquery $.json2html call).

let data = [
    {'id':'100','children':[
        {'name':'this'},
        {'name':'is'},
        {'name':'great!'}
    ]},
    {'id':'101','children':[
        {'name':'this'},
        {'name':'is'},
        {'name':'amazing!'}
    ]}
];

let templates = {
    'parent': {'<>':'div','id':'${id}','html':function(obj,index){
        return $.json2html(
                    this.children,
                    templates.child));
    },
    'child':{'<>':'span','html':'${name}'}
};

$('ul').json2html(data,templates.parent);
<ul>
<li id=100>
    <span>this</span>
    <span>is</span>
    <span>great!</span>
</li>
<li id=101>
    <span>this</span>
    <span>is</span>
    <span>amazing!</span>
</li>
obj attribute

The reserved obj attribute can be used to specify the object that you want this template (and any child templates) to render. Unlike other attributes you MUST specify this as a function with the returned value being the object you wish to render.


let data = [
    {'department':'finance','employees':[
        {'name':'dorian'},
        {'name':'monica'}
    ]}
];    

let template = [
    {'<>':'h1','text':'${department}'},
    {'<>':'ul','html':[
        {'<>':'li','text':'${name}','obj':function(){return(this.employees)}}
    ]}
];
<h1>finance</h1>
<ul>
    <li>dorian</li>
    <li>monica</li>
</div> 

Keep in mind that any children will also use the same object as the one specified by its parent.


let data = [
    {'department':'finance','employees':[
        {'name':'dorian','salary':'$40,000'},
        {'name':'monica','salary':'$60,000'}
    ]}
];    

let template = [
    {'<>':'h1','text':'${department}'},
    {'<>':'ul','html':[
        {'<>':'li','obj':function(){return(this.employees)},'html':[
            {'<>':'span','text':'${name}'},
            {'<>':'strong','text':'(${salary})'}
        ]}
    ]}
];
<h1>finance</h1>
<ul>
    <li>
        <span>dorian</span>
        <strong>($40,000)</strong>
    </li>
    <li>
        <span>monica</span>
        <strong>($60,000)</strong>
    </li>
</div> 
dom specific attributes

All other dom attributes are supported (eg 'id', 'class', 'style', 'data-*', 'href' etc..).

{'<>':'div','id':'id-123','class':'red','data-id':'123','text':'some text'}
<div id='id-123' class='red' data-id='123' >some text</div>
events

Using the jquery wrapper allows for events to be embedded within a template. These events will be automatically attached when the template is applied to the DOM using a jquery selector function eg. $('ul').json2html(..))

Event attributes (onclick, onfocus, onmouseout etc..) are created by adding an event handler to the DOM element using jquery, each handler requires an inline function to evaulate when the event is triggered. Supported events include all jQuery events that can be attached to a DOM element, simply add the 'on' prefix to the following found on the jQuery events page

Here's a partial list of the supported events, with the required 'on' prefix added

  • onclick
  • onblur
  • ondblclick
  • ondie
  • onerror
  • onchange
  • onhover
  • onfocus
  • etc..

{'<>':'button','onclick':function(e){
    //e.event : the jQuery event
    //e.data  : user specified data from the the json2html options variable data (see Usage)
    //e.obj   : the source object that we're rendering
    //e.index : the index of the array in which the source object was found
}}
{'<>':'button','html':'click me','onclick':function(e){
    console.log(e.obj.name);
}
<button>click me</button>

In addition to jquery events there's an added event 'onready' which will be triggered once the template has been rendered.

{'<>':'div','onready':function(e){
    //triggered once the div has been rendered and is available to the dom
}}

The jquery element that called the event can also be accessed using $(this); which is the same as referencing e.event.target in the example above

{'<>':'span','onclick':function(){
    $(this).hide();
}
<span>click me</span>

Assignment

To assign data from the object your rendering you'll need to use one of the following assignment methods

Literals

You can assign literal text to any of the dom attributes of a template.

{'<>':'div','id':'some-div','class':'some-class','html':'some stuff'}
<div id='some-div' class='some-class' >some stuff</div>
shorthand

Shorthand notation is the easiest way to map data into your template, simply specify the variable in the format ${name} where name is the variable name within the data object. This variable will then be inserted into that attribute during render.

{'<>':'div','id':'${id}','class':'${highlight}','text':'${title} is amazing!'}
<div id='1' class='red'>Fast and the Furious: Part 2 is amazing!</div>

The above example will map the data 'title' to the inner text of the div, it will also use the variable 'highlight' as the class name and 'id' for the id of the DOM object. You can also use reference sub objects with a '.' like address.state or address.0 if the object is an array:

{'<>':'div','text':'${movie.0.title} is amazing!'}
<div>Fast and the Furious is amazing!</div>

The above example will map the source JSON field movie [0].title to the inner text of the div.

inline function

Inline functions can be used to embed logic to assign property values to any dom attributes including the reserved attributes (<>, [], html and text).

{'<>':'div','class':function(){return('red');},'html':'this is in red'}
<div class='red'>this is in red</div>

json2html will pass the data object to the function as a parameter as well as the index in the array of objects that it was found, allowing for the function to process the fields in any manner.

{'<>':'div','html':function(obj,index){
                        return(obj.title + ': ' + obj.date);
                    }}
<div>Fast and the Furious : May 10th 2011</div>

Alternatively, the data object can also be referenced using the key word 'this'

{'<>':'div','html':function(){return(this.title + ': ' + this.date);}}
<div>Fast and the Furious : May 10th 2011</div>

Note the above example could also be done using short-hand notation, as follows

{'<>':'div','html':'${title} : ${date}'}
<div>Fast and the Furious : May 10th 2011</div>

When using an inline function you can also reference the index of the object you're rendering if your data object is an array

{'<>':'li','html':function(obj,index){
                        return(index + ". " + obj.title);
                    }}
<ul>
    <li>0. Fast and the Furious</li>
    <li>1. The Avengers</li>
    <li>2. Iron Man</li>
</ul>
arrays

If the object your rendering an array of literals (ie non objects) you can reference each element in the array by using the keyword 'value' and the index using the keywork 'index'. Note that these keywords only work with arrays or literals and not arrays of objects

{'<>':'tr','html':
    {'<>':'td','text':'${index} - ${value}'}
}
<tr><td>0 - first element value</td></tr>
<tr><td>1 - second element value</td></tr>
<tr><td>2 - thrid element value</td></tr>

You can also reference the keywords within a function using longhand notation this.index and this.value


{'<>':'tr','html':
    {'<>':'td','text':function(){
        return(this.index + '- ' + this.value);
    }}
}
<tr><td>0 - first element value</td></tr>
<tr><td>1 - second element value</td></tr>
<tr><td>2 - thrid element value</td></tr>

Blocks

Blocks are templates that don't produce dom objects instead they can be used to insert raw text/html or map data to child templates. Unlike dom templates you can only use the following reserved attributes

  • obj specifies the obj that this template should render
  • text specifies a string of text (or inline function that returns text)
  • html specifies the html string (or array of child templates)
html attribute

Use the 'html' reserved attribute to insert raw html, just like you would with a dom template


let data = [
    {'name':'dorian'},
    {'name':'monica'}
];

let template = {'html':'<li>${name}</li>'}
<li>dorian!</li>
<li>monica!</li>

or use to specify a block of templates (dom, component or blocks). This works well when maping a data object to the entire block (see obj attribute below for example)

{'html':[
    {'<>':'p','text':'hi there!'},
    {'html':'we like stuff'},
    {'[]':'link'}
]}
<p>hi there!</p>
we like stuff
<a href='https://example.org'>click me!</a>

or just like the dom template a function with the result being either an html string or an iHTML object

{'html':function(){return("hello");}}
hello
text attribute

Just like a dom template the text attribute will only render text, encoding all html specific characters and can be used to help prevent xss injection attacks.

{'text':'<span>read this as text</span>'}
&lt;span&gt;read this as text&lt;/span&gt;

and just like a dom template the text attribute can also be a function with the return value being text.


let data = {'name':'dorian'}    

let template = {'text':function(){return(this.name}}
dorian
obj attribute

Use the 'obj' reserved attribute specify the object that you want to render with this template block and all its children. Note that you MUST use a function with the return value being object (or array) you want to render for this template. The parameters for this function will be the (obj,index) and 'this' will be mapped to the source parent object.


let data = {
    "employees":[
        {'name':'dorian','role':'CEO'},
        {'name':'monica','role':'CFO'}
    ]
};

let template = {'obj':function(){return(this.employees)},'html':[
        {'<>':'div','html':[
            {'<>':'span','text':'${name}'},
            {'<>':'span','text':'(${role})'}
        ]}
    ]};
<div> 
    <span>dorian!</span>
    <span>CEO!</span>
</div>   
<div> 
    <span>monica!</span>
    <span>CFO!</span>
</div>  

Components

Components are an easy way to create re-usable templates. They can be embedded within templates or used as wrappers around templates. You can create them using the following reserved attributes

  • [] specifies the name of the component
  • obj specifies the obj that this template should render
  • html specifies the array of child templates we want to wrap with this component
[] attribute

Each component is designed using the reserved '[]' attribute with the name of the component.

{'[]':'item'}
register

Before a component can be used it must first be registered. Use the json2html.component.add(name,template) method to register your component and its friendly name (which will be used to reference the component)

json2html.component.add("item",{'<>':'li','text':'${title} is amazing!'});

Note: you can always use the json2html.component.get(name) to get the component directly if required

Components can also be registered on mass using the json2html.component.add(components) where components is an object with name value pairs of components

json2html.component.add({
    'list':{'<>':'ul','html':[{[]:"item"}]},
    'item':{'<>':'li','text':'${title} is amazing!'}
});
usage

Once a component is registered you can use it within the same scope as your json2html.render call (for the browser this means the same page or for node.js this means the same scope as the require library call)

By default the component uses the same data object as its parent, in the case below this is the same data object that was being rendered.

json2html.component.add('link',{'<>':'a','href':'${url}','text':'${title}'});

let template = [
    {'<>':'h1','text':'${heading}'},
    {'[]':'link'}
];

let data = {
    'heading';'Search Engine',
    'title':'Google Search',
    'url':'https://www.google.com'
};

json2html.render(data,template);
<h1>Search Engine</h1>
<a href='https://www.google.com'>Google Search</a>
obj attribute

To make the component more useful you can specify the object you want the component to render, this can be done using the reserved 'obj' attribute.

Unlike dom template attributes (specified with the <>) components only have two reserved attributes 'obj' and 'html'. The 'obj' attribute uses a function call to specify what object this component should render, by default this object is the same as it's parent (or original json2html.render call). You can access the keyword 'this' to access the data object that we are rendering within the 'data' function.

json2html.component.add('movie',{'<>':'li','text':'${title} is amazing!'});

let template = [
    {'<>':'h1','text':'${name}'},
    {'<>':'ul','html':[
        {'[]':'movie','obj':function(){return(this.movies);}
    ]};

let data = {
    'name':'My Movie List',
    'movies':[
        {'title':'Lonely Hearts'},
        {'title':'National Treasure'}
    ]};

json2html.render(data,template);
<h1>My Movie List</h1>
<ul> 
    <li>Lonley Hearts is amazing!</li>
    <li>National Treasure is amazing!</li>
</ul>
hthml attribute

In addition to using components as children within templates you can also use them as parents in order to create a type of wrapper around a template. This helps when creating re-usable components that wrap templates, like a page heading.

This is done using the reserved 'html' attribute for the component, which can take another json2html template (array or object). You can then use the template you've wrapped in your component by accessing the html parameter from your 'html' attribute function call like the example below.

json2html.component.add('page',
    {'<>':'section','html':[
        {'<>':'h1','text':'${title}'},
        {'<>':'div','html':function(obj,index,data,html){return(html);}}
    ]});

let template = [
    {'[]':'page','html':[
        {'<>':'p','text':'${content}'}
    ]};

let data = {
    'title':'My First Page',
    'content':'my custom page content'
};

json2html.render(data,template);
<section>
    <h1>My First Page!</h1>
    <div>
        <p>my custom page content</p>
    </div>
</section>