Toggle query string variables - javascript

I've been banging my head over this.
Using jquery or javascript, how can I toggle variables & values and then rebuild the query string? For example, my starting URL is:
http://example.com?color=red&size=small,medium,large&shape=round
Then, if the user clicks a button labeled "red", I want to end up with:
http://example.com?size=small,medium,large&shape=round //color is removed
Then, if the user clicks "red" again, I want to end up with:
http://example.com?size=small,medium,large&shape=round&color=red //color is added back
Then, if the user clicks a button labeled "medium", I want to end up with:
http://example.com?size=small,large&shape=round&color=red //medium is removed from list
Then, if the user clicks the labeled "medium" again, I want to end up with:
http://example.com?size=small,large,medium&shape=round&color=red //medium added back
It doesn't really matter what order the variable are in; I've just been tacking them to the end.

function toggle(url, key, val) {
var out = [],
upd = '',
rm = "([&?])" + key + "=([^&]*?,)?" + val + "(,.*?)?(&.*?)?$",
ad = key + "=",
rmrplr = function(url, p1, p2, p3, p4) {
if (p2) {
if (p3) out.push(p1, key, '=', p2, p3.substr(1));
else out.push(p1, key, '=', p2.substr(0, p2.length - 1));
} else {
if (p3) out.push(p1, key, '=', p3.substr(1));
else out.push(p1);
}
if (p4) out.push(p4);
return out.join('').replace(/([&?])&/, '$1').replace(/[&?]$/, ''); //<!2
},
adrplr = function(s) {
return s + val + ',';
};
if ((upd = url.replace(new RegExp(rm), rmrplr)) != url) return upd;
if ((upd = url.replace(new RegExp(ad), adrplr)) != url) return upd;
return url + (/\?.+/.test(url) ? '&' : '?') + key + '=' + val; //<!1
}
params self described enough, hope this help.
!1: changed from ...? '&' : '' to ... ? '&' : '?'
!2: changed from .replace('?&','?')... to .replace(/([&?]&)/,'$1')...
http://jsfiddle.net/ycw7788/Abxj8/

I have written a function, which efficiently results in the expected behaviour, without use of any libraries or frameworks. A dynamic demo can be found at this fiddle: http://jsfiddle.net/w8D2G/1/
Documentation
Definitions:
The shown example values will be used at the Usage section, below
  -   Haystack - The string to search in (default = query string. e.g: ?size=small,medium)
  -   Needle - The key to search for. Example: size
  -   Value - The value to replace/add. Example: medium.
Usage (Example: input > output):
qs_replace(needle, value)
If value exists, remove: ?size=small,medium > ?size=small
If value not exists, add: ?size=small > size=small,medium
qs_replace(needle, options)     Object options. Recognised options:
findString. Returns true if the value exists, false otherwise.
add, remove or toggleString. Add/remove the given value to/from needle. If remove is used, and the value was the only value, needle is also removed. A value won't be added if it already exists.
ignorecaseIgnore case while looking for the search terms (needle, add, remove or find).
separatorSpecify a separator to separate values of needle. Default to comma (,).
Note :   A different value for String haystack can also be defined, by adding it as a first argument: qs_replace(haystack, needle, value) or qs_replace(haystack, needle, options)
Code (examples at bottom). Fiddle: http://jsfiddle.net/w8D2G/1/:
function qs_replace(haystack, needle, options) {
if(!haystack || !needle) return ""; // Without a haystack or needle.. Bye
else if(typeof needle == "object") {
options = needle;
needle = haystack;
haystack = location.search;
} else if(typeof options == "undefined") {
options = needle;
needle = haystack;
haystack = location.search;
}
if(typeof options == "string" && options != "") {
options = {remove: options};
var toggle = true;
} else if(typeof options != "object" || options === null) {
return haystack;
} else {
var toggle = !!options.toggle;
if (toggle) {
options.remove = options.toggle;
options.toggle = void 0;
}
}
var find = options.find,
add = options.add,
remove = options.remove || options.del, //declare remove
sep = options.sep || options.separator || ",", //Commas, by default
flags = (options.ignorecase ? "i" :"");
needle = encodeURIComponent(needle); //URL-encoding
var pattern = regexp_special_chars(needle);
pattern = "([?&])(" + pattern + ")(=|&|$)([^&]*)(&|$)";
pattern = new RegExp(pattern, flags);
var subquery_match = haystack.match(pattern);
var before = /\?/.test(haystack) ? "&" : "?"; //Use ? if not existent, otherwise &
var re_sep = regexp_special_chars(sep);
if (!add || find) { //add is not defined, or find is used
var original_remove = remove;
if (subquery_match) {
remove = encodeURIComponent(remove);
remove = regexp_special_chars(remove);
remove = "(^|" + re_sep + ")(" + remove + ")(" + re_sep + "|$)";
remove = new RegExp(remove, flags);
var fail = subquery_match[4].match(remove);
} else {
var fail = false;
}
if (!add && !fail && toggle) add = original_remove;
}
if(find) return !!subquery_match || fail;
if (add) { //add is a string, defined previously
add = encodeURIComponent(add);
if(subquery_match) {
var re_add = regexp_special_chars(add);
re_add = "(^|" + re_sep + ")(" + re_add + ")(?=" + re_sep + "|$)";
re_add = new RegExp(re_add, flags);
if (subquery_match && re_add.test(subquery_match[4])) {
return haystack;
}
if (subquery_match[3] != "=") {
subquery_match = "$1$2=" + add + "$4$5";
} else {
subquery_match = "$1$2=$4" + sep + add + "$5";
}
return haystack.replace(pattern, subquery_match);
} else {
return haystack + before + needle + "=" + add;
}
} else if(subquery_match){ // Remove part. We can only remove if a needle exist
if(subquery_match[3] != "="){
return haystack;
} else {
return haystack.replace(pattern, function(match, prefix, key, separator, value, trailing_sep){
// The whole match, example: &foo=bar,doo
// will be replaced by the return value of this function
var newValue = value.replace(remove, function(m, pre, bye, post){
return pre == sep && post == sep ? sep : pre == "?" ? "?" : "";
});
if(newValue) { //If the value has any content
return prefix + key + separator + newValue + trailing_sep;
} else {
return prefix == "?" ? "?" : trailing_sep; //No value, also remove needle
}
}); //End of haystack.replace
} //End of else if
} else {
return haystack;
}
// Convert string to RegExp-safe string
function regexp_special_chars(s){
return s.replace(/([[^$.|?*+(){}\\])/g, '\\$1');
}
}
Examples (Fiddle: http://jsfiddle.net/w8D2G/1/):
qs_replace('color', 'red'); //Toggle color=red
qs_replace('size', {add: 'medium'}); //Add `medium` if not exist to size
var starting_url = 'http://example.com?color=red&size=small,medium,large&shape=round'
starting_url = qs_replace(starting_url, 'color', 'red'); //Toggle red, thus remove
starting_url = qs_replace(starting_url, 'color', 'red'); //Toggle red, so add it
alert(starting_url);

This is the solution for your task: http://jsfiddle.net/mikhailov/QpjZ3/12/
var url = 'http://example.com?size=small,medium,large&shape=round';
var params = $.deparam.querystring(url);
var paramsResult = {};
var click1 = { size: 'small' };
var click2 = { size: 'xlarge' };
var click3 = { shape: 'round' };
var click4 = { shape: 'square' };
var clickNow = click4;
for (i in params) {
var clickKey = _.keys(clickNow)[0];
var clickVal = _.values(clickNow)[0];
if (i == clickKey) {
var ar = params[i].split(',');
if (_.include(ar, clickVal)) {
var newAr = _.difference(ar, [clickVal]);
} else {
var newAr = ar;
newAr.push(clickVal);
}
paramsResult[i] = newAr.join(',');
} else {
paramsResult[i] = params[i];
}
}
alert($.param(paramsResult)) // results see below
Init params string
{ size="small, medium,large", shape="round"} // size=small,medium,large&shape=round
Results
{ size="small"} => { size="medium,large", shape="round"} //size=medium%2Clarge&shape=round
{ size="xlarge"} => { size="small,medium,large,xlarge", shape="round"} // size=small%2Cmedium%2Clarge%2Cxlarge&shape=round
{ shape="round"} => { size="small,medium,large", shape=""} //size=small%2Cmedium%2Clarge&shape=
{ shape="square"} => { size="small,medium,large", shape="round,square"} //size=small%2Cmedium%2Clarge&shape=round%2Csquare

productOptions is the only thing you need to modify here to list all the available options and their default state. You only need to use the public API function toggleOption() to toggle an option.
(function(){
//Just keep an object with all the options with flags if they are enabled or disabled:
var productOptions = {
color: {
"red": true,
"blue": true,
"green": false
},
size: {
"small": true,
"medium": true,
"large": true
},
shape: {
"round": true
}
};
//After this constructing query becomes pretty simple even without framework functions:
function constructQuery(){
var key, opts, qs = [], enc = encodeURIComponent, opt,
optAr, i;
for( key in productOptions ) {
opts = productOptions[key];
optAr = [];
for( i in opts ) {
if( opts[i] ) {
optAr.push( i );
}
}
if( !optAr.length ) {
continue;
}
qs.push( enc( key ) + "=" + enc( optAr.join( "," ) ) );
}
return "?"+qs.join( "&" );
};
//To toggle a value and construct the new query, pass what you want to toggle to this function:
function toggleOption( optionType, option ) {
if( optionType in productOptions && option in productOptions[optionType] ) {
productOptions[optionType][option] = !productOptions[optionType][option];
}
return constructQuery();
}
window.toggleOption = toggleOption;
})()
Example use:
// "%2C" = url encoded version of ","
toggleOption(); //Default query returned:
"?color=red%2Cblue&size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "color", "red" ); //Red color removed:
"?color=blue&size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "color", "blue" ); //Blue color removed, no color options so color doesn't show up at all:
"?size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "color", "blue" ); //Blue color enabled again:
"?color=blue&size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "shape", "round" ); //The only shape option removed
"?color=blue&size=small%2Cmedium%2Clarge"

I have tried this and this may give the desire result
<script>
var url='http://example.com?color=red&size=small,medium,large&shape=round';
var mySplitResult = url.split("?");
var domain=mySplitResult[0];
var qstring=mySplitResult[1];
var proparr=new Array();
var valarr=new Array();
var mySplitArr = qstring.split("&");
for (i=0;i<mySplitArr.length;i++){
var temp = mySplitArr[i].split("=");
proparr[i]=temp[0];
valarr[i]=temp[1].split(",");
}
function toggle(property,value)
{
var index;
var yes=0;
for (i=0;i<proparr.length;i++){
if(proparr[i]==property)
index=i;
}
if(index==undefined){
proparr[i]=property;
index=i;
valarr[index]=new Array();
}
for (i=0;i<valarr[index].length;i++){
if(valarr[index][i]==value){
valarr[index].splice(i,1);
yes=1;
}
}
if(!yes)
{
valarr[index][i]=value;
}
var furl=domain +'?';
var test=new Array();
for(i=0;i<proparr.length;i++)
{
if(valarr[i].length)
{
test[i]=valarr[i].join(",");
furl +=proparr[i]+"="+test[i]+"&";
}
}
furl=furl.substr(0,furl.length-1)
alert(furl);
}
</script>
<div>
<input id="color" type="button" value="Toggle Red" onclick="toggle('color','red')"/>
<input id="shape" type="button" value="Toggle shape" onclick="toggle('shape','round')"/>
<input id="size" type="button" value="Toggle Small" onclick="toggle('size','small')"/>
<input id="size" type="button" value="Toggle large" onclick="toggle('size','large')"/>
<input id="size" type="button" value="Toggle medium" onclick="toggle('size','medium')"/>
<input id="size" type="button" value="Toggle new" onclick="toggle('new','yes')"/>
</div>

Related

query string takes off last ')' in url

I am constructing a query string in Javascript based on whether a checkbox is checked or not.
Some of the options in the checkboxes are
"Annual"
"Grass"
"Shrub (Evergreen)"
"Shrub (Deciduous)"
I found a function online that updates the url parameter:
function updateUrlParameter(uri, key, value) {
value = value.replace(/\s/g, "%20");
var i = uri.indexOf('#');
var hash = i === -1 ? '' : uri.substr(i);
uri = i === -1 ? uri : uri.substr(0, i);
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (!value) {
// remove key-value pair if value is empty
uri = uri.replace(new RegExp("([&]?)" + key + "=.*?(&|$)", "i"), '');
if (uri.slice(-1) === '?') {
uri = uri.slice(0, -1);
}
} else {
console.log("value is " + value)
uri = uri + separator + key + "=" + value;
}
return uri + hash;
}
Using the above function, if I check the checkboxes for the above four starting from top down, my query string becomes
?plantType=Annual&plantType=Grass&plantType=Shrub%20(Evergreen)&plantType=Shrub%20(Deciduous
Why is the function ignoring the last ')' in the string? Is there a work around this? I would like to keep the parenthesis in the query string because this will make querying the database easier.
I created a function to iterate through input checkboxes. If they are checked, then use the updateUrlParameter function to update the URI.
function getQueryString() {
var inputsContainerChildren = $('#floatingDivForFilter').children();
var input = document.createElement('input')
var uri = '';
for (var i = 0; i < inputsContainerChildren.length; i++) {
var currChild = inputsContainerChildren[i].firstElementChild;
if (currChild) {
if (currChild.tagName === 'INPUT') {
if (currChild.checked) {
var id = currChild.id;
console.log(uri)
uri = updateUrlParameter(uri, currChild.name, currChild.value);
}
}
}
}
console.log(uri);
}
The photo below shows a snapshot of the URL produced. I can't figure out why the last ')' is chopped off.
url photo
The issue you are seeing is just the Chrome developer tools trying to be too clever.
When logging the url to the console, Chrome will not recognize the full url as a link but exclude the closing ")". They probably do that because it will be very common that people write an url in braces and it is not expected that the closing brace is part of the url.
Since this is only an issue of the developer tools, you can ignore the issue. It will not affect the runtime behaviour of your code.
The issue will be solved when you correctly escape special characters in the parameters (as you should do anyway):
function updateUrlParameter(uri, key, value) {
// removed because escape will do that
// value = value.replace(/\s/g, "%20");
var i = uri.indexOf('#');
var hash = i === -1 ? '' : uri.substr(i);
uri = i === -1 ? uri : uri.substr(0, i);
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (!value) {
// remove key-value pair if value is empty
uri = uri.replace(new RegExp("([&]?)" + key + "=.*?(&|$)", "i"), '');
if (uri.slice(-1) === '?') {
uri = uri.slice(0, -1);
}
} else {
console.log("value is " + value)
// Use escape on key and value
uri = uri + separator + escape(key) + "=" + escape(value);
}
return uri + hash;
}
let s = "http://chrome.is.too.clever/";
s = updateUrlParameter(s, "plantType", "Annual");
s = updateUrlParameter(s, "plantType", "Grass");
s = updateUrlParameter(s, "plantType", "Shrub (Evergreen)");
s = updateUrlParameter(s, "plantType", "Shrub (Deciduous)");
console.log(s);
Fiddle
Instead of using a regular expression, just convert the params to an object, modify said object, and convert it back into params.
var url = 'https://x.y?plantType=Annual&plantType=Grass&plantType=Shrub%20(Evergreen)&plantType=Shrub%20(Deciduous)';
function updateUrlParameter(uri, key, value) {
let url = new URL(uri), object = deserializeQuery(url.search); // params to obj
object[key] = value; // modify obj
return url.origin + '?' + serializeQuery(object); // obj to url + params
}
console.log(updateUrlParameter(url, 'plantType', [ 'Pine', 'Palm', 'Rose (Red)' ]));
/** ======= Serialization / Deserialization functions below ======== */
// https://stackoverflow.com/a/47517503/1762224
function deserializeQuery(queryString, queryKey) {
let query = {}, pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('='), key = decodeURIComponent(pair[0]), value = decodeURIComponent(pair[1] || '');
value = (value.indexOf(',') === -1 ? value : value.split(','));
query[key] = query[key] ? (query[key].constructor === Array ? query[key].concat(value) : [query[key], value]) : value;
}
return typeof queryKey === 'undefined' ? query : query[queryKey];
}
// https://stackoverflow.com/a/53528203/1762224
function serializeQuery(params, keys = [], isArray = false) {
const p = Object.keys(params).map(key => {
let val = params[key];
if ("[object Object]" === Object.prototype.toString.call(val) || Array.isArray(val)) {
keys.push(Array.isArray(params) ? "" : key);
return serializeQuery(val, keys, Array.isArray(val));
} else {
let tKey = keys.length > 0 ? ((isArray ? keys : [...keys, key]).reduce((str, k) => "" === str ? k : `${str}[${k}]`, "")) : key;
if (isArray) {
return encodeURIComponent(tKey) + '=' + encodeURIComponent(val);
}
}
}).join('&');
keys.pop();
return p;
}
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}
.as-console-row {
white-space: pre-wrap;
word-break: break-all;
}

How to output json prettry formt as html using javascript? [duplicate]

How can I display JSON in an easy-to-read (for human readers) format? I'm looking primarily for indentation and whitespace, with perhaps even colors / font-styles / etc.
Pretty-printing is implemented natively in JSON.stringify(). The third argument enables pretty printing and sets the spacing to use:
var str = JSON.stringify(obj, null, 2); // spacing level = 2
If you need syntax highlighting, you might use some regex magic like so:
function syntaxHighlight(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
See in action here: jsfiddle
Or a full snippet provided below:
function output(inp) {
document.body.appendChild(document.createElement('pre')).innerHTML = inp;
}
function syntaxHighlight(json) {
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
var obj = {a:1, 'b':'foo', c:[false,'false',null, 'null', {d:{e:1.3e5,f:'1.3e5'}}]};
var str = JSON.stringify(obj, undefined, 4);
output(str);
output(syntaxHighlight(str));
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
.null { color: magenta; }
.key { color: red; }
User Pumbaa80's answer is great if you have an object you want pretty printed. If you're starting from a valid JSON string that you want to pretty printed, you need to convert it to an object first:
var jsonString = '{"some":"json"}';
var jsonPretty = JSON.stringify(JSON.parse(jsonString),null,2);
This builds a JSON object from the string, and then converts it back to a string using JSON stringify's pretty print.
Better way.
Prettify JSON Array in Javascript
JSON.stringify(jsonobj,null,'\t')
var jsonObj = {"streetLabel": "Avenue Anatole France", "city": "Paris 07", "postalCode": "75007", "countryCode": "FRA", "countryLabel": "France" };
document.getElementById("result-before").innerHTML = JSON.stringify(jsonObj);
In case of displaying in HTML, you should to add a balise <pre></pre>
document.getElementById("result-after").innerHTML = "<pre>"+JSON.stringify(jsonObj,undefined, 2) +"</pre>"
Example:
var jsonObj = {"streetLabel": "Avenue Anatole France", "city": "Paris 07", "postalCode": "75007", "countryCode": "FRA", "countryLabel": "France" };
document.getElementById("result-before").innerHTML = JSON.stringify(jsonObj);
document.getElementById("result-after").innerHTML = "<pre>"+JSON.stringify(jsonObj,undefined, 2) +"</pre>"
div { float:left; clear:both; margin: 1em 0; }
<div id="result-before"></div>
<div id="result-after"></div>
Based on Pumbaa80's answer I have modified the code to use the console.log colours (working on Chrome for sure) and not HTML. Output can be seen inside console. You can edit the _variables inside the function adding some more styling.
function JSONstringify(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, '\t');
}
var
arr = [],
_string = 'color:green',
_number = 'color:darkorange',
_boolean = 'color:blue',
_null = 'color:magenta',
_key = 'color:red';
json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var style = _number;
if (/^"/.test(match)) {
if (/:$/.test(match)) {
style = _key;
} else {
style = _string;
}
} else if (/true|false/.test(match)) {
style = _boolean;
} else if (/null/.test(match)) {
style = _null;
}
arr.push(style);
arr.push('');
return '%c' + match + '%c';
});
arr.unshift(json);
console.log.apply(console, arr);
}
Here is a bookmarklet you can use:
javascript:function JSONstringify(json) {if (typeof json != 'string') {json = JSON.stringify(json, undefined, '\t');}var arr = [],_string = 'color:green',_number = 'color:darkorange',_boolean = 'color:blue',_null = 'color:magenta',_key = 'color:red';json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {var style = _number;if (/^"/.test(match)) {if (/:$/.test(match)) {style = _key;} else {style = _string;}} else if (/true|false/.test(match)) {style = _boolean;} else if (/null/.test(match)) {style = _null;}arr.push(style);arr.push('');return '%c' + match + '%c';});arr.unshift(json);console.log.apply(console, arr);};void(0);
Usage:
var obj = {a:1, 'b':'foo', c:[false,null, {d:{e:1.3e5}}]};
JSONstringify(obj);
Edit: I just tried to escape the % symbol with this line, after the variables declaration:
json = json.replace(/%/g, '%%');
But I find out that Chrome is not supporting % escaping in the console. Strange... Maybe this will work in the future.
Cheers!
I think you're looking for something like this :
JSON.stringify(obj, null, '\t');
This "pretty-prints" your JSON string, using a tab for indentation.
If you prefer to use spaces instead of tabs, you could also use a number for the number of spaces you'd like :
JSON.stringify(obj, null, 2);
You can use console.dir(), which is a shortcut for console.log(util.inspect()).
(The only difference is that it bypasses any custom inspect() function defined on an object.)
It uses syntax-highlighting, smart indentation, removes quotes from keys and just makes the output as pretty as it gets.
const object = JSON.parse(jsonString)
console.dir(object, {depth: null, colors: true})
and for the command line:
cat package.json | node -e "process.stdin.pipe(new stream.Writable({write: chunk => console.dir(JSON.parse(chunk), {depth: null, colors: true})}))"
I use the JSONView Chrome extension (it is as pretty as it gets :):
Edit: added jsonreport.js
I've also released an online stand-alone JSON pretty print viewer, jsonreport.js, that provides a human readable HTML5 report you can use to view any JSON data.
You can read more about the format in New JavaScript HTML5 Report Format.
If you are using ES5, simply call JSON.stringify with:
2nd arg: replacer; set to null,
3rd arg: space; use tab.
JSON.stringify(anObject, null, '\t');
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Here's user123444555621's awesome HTML one adapted for terminals. Handy for debugging Node scripts:
function prettyJ(json) {
if (typeof json !== 'string') {
json = JSON.stringify(json, undefined, 2);
}
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
function (match) {
let cls = "\x1b[36m";
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = "\x1b[34m";
} else {
cls = "\x1b[32m";
}
} else if (/true|false/.test(match)) {
cls = "\x1b[35m";
} else if (/null/.test(match)) {
cls = "\x1b[31m";
}
return cls + match + "\x1b[0m";
}
);
}
Usage:
// thing = any json OR string of json
prettyJ(thing);
For debugging purpose I use:
console.debug("%o", data);
https://getfirebug.com/wiki/index.php/Console_API
https://developer.mozilla.org/en-US/docs/DOM/console
You can use JSON.stringify(your object, null, 2)
The second parameter can be used as a replacer function which takes key and Val as parameters.This can be used in case you want to modify something within your JSON object.
more reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Unsatisfied with other pretty printers for Ruby, I wrote my own (NeatJSON) and then ported it to JavaScript including a free online formatter. The code is free under MIT license (quite permissive).
Features (all optional):
Set a line width and wrap in a way that keeps objects and arrays on the same line when they fit, wrapping one value per line when they don't.
Sort object keys if you like.
Align object keys (line up the colons).
Format floating point numbers to specific number of decimals, without messing up the integers.
'Short' wrapping mode puts opening and closing brackets/braces on the same line as values, providing a format that some prefer.
Granular control over spacing for arrays and objects, between brackets, before/after colons and commas.
Function is made available to both web browsers and Node.js.
I'll copy the source code here so that this is not just a link to a library, but I encourage you to go to the GitHub project page, as that will be kept up-to-date and the code below will not.
(function(exports){
exports.neatJSON = neatJSON;
function neatJSON(value,opts){
opts = opts || {}
if (!('wrap' in opts)) opts.wrap = 80;
if (opts.wrap==true) opts.wrap = -1;
if (!('indent' in opts)) opts.indent = ' ';
if (!('arrayPadding' in opts)) opts.arrayPadding = ('padding' in opts) ? opts.padding : 0;
if (!('objectPadding' in opts)) opts.objectPadding = ('padding' in opts) ? opts.padding : 0;
if (!('afterComma' in opts)) opts.afterComma = ('aroundComma' in opts) ? opts.aroundComma : 0;
if (!('beforeComma' in opts)) opts.beforeComma = ('aroundComma' in opts) ? opts.aroundComma : 0;
if (!('afterColon' in opts)) opts.afterColon = ('aroundColon' in opts) ? opts.aroundColon : 0;
if (!('beforeColon' in opts)) opts.beforeColon = ('aroundColon' in opts) ? opts.aroundColon : 0;
var apad = repeat(' ',opts.arrayPadding),
opad = repeat(' ',opts.objectPadding),
comma = repeat(' ',opts.beforeComma)+','+repeat(' ',opts.afterComma),
colon = repeat(' ',opts.beforeColon)+':'+repeat(' ',opts.afterColon);
return build(value,'');
function build(o,indent){
if (o===null || o===undefined) return indent+'null';
else{
switch(o.constructor){
case Number:
var isFloat = (o === +o && o !== (o|0));
return indent + ((isFloat && ('decimals' in opts)) ? o.toFixed(opts.decimals) : (o+''));
case Array:
var pieces = o.map(function(v){ return build(v,'') });
var oneLine = indent+'['+apad+pieces.join(comma)+apad+']';
if (opts.wrap===false || oneLine.length<=opts.wrap) return oneLine;
if (opts.short){
var indent2 = indent+' '+apad;
pieces = o.map(function(v){ return build(v,indent2) });
pieces[0] = pieces[0].replace(indent2,indent+'['+apad);
pieces[pieces.length-1] = pieces[pieces.length-1]+apad+']';
return pieces.join(',\n');
}else{
var indent2 = indent+opts.indent;
return indent+'[\n'+o.map(function(v){ return build(v,indent2) }).join(',\n')+'\n'+indent+']';
}
case Object:
var keyvals=[],i=0;
for (var k in o) keyvals[i++] = [JSON.stringify(k), build(o[k],'')];
if (opts.sorted) keyvals = keyvals.sort(function(kv1,kv2){ kv1=kv1[0]; kv2=kv2[0]; return kv1<kv2?-1:kv1>kv2?1:0 });
keyvals = keyvals.map(function(kv){ return kv.join(colon) }).join(comma);
var oneLine = indent+"{"+opad+keyvals+opad+"}";
if (opts.wrap===false || oneLine.length<opts.wrap) return oneLine;
if (opts.short){
var keyvals=[],i=0;
for (var k in o) keyvals[i++] = [indent+' '+opad+JSON.stringify(k),o[k]];
if (opts.sorted) keyvals = keyvals.sort(function(kv1,kv2){ kv1=kv1[0]; kv2=kv2[0]; return kv1<kv2?-1:kv1>kv2?1:0 });
keyvals[0][0] = keyvals[0][0].replace(indent+' ',indent+'{');
if (opts.aligned){
var longest = 0;
for (var i=keyvals.length;i--;) if (keyvals[i][0].length>longest) longest = keyvals[i][0].length;
var padding = repeat(' ',longest);
for (var i=keyvals.length;i--;) keyvals[i][0] = padRight(padding,keyvals[i][0]);
}
for (var i=keyvals.length;i--;){
var k=keyvals[i][0], v=keyvals[i][1];
var indent2 = repeat(' ',(k+colon).length);
var oneLine = k+colon+build(v,'');
keyvals[i] = (opts.wrap===false || oneLine.length<=opts.wrap || !v || typeof v!="object") ? oneLine : (k+colon+build(v,indent2).replace(/^\s+/,''));
}
return keyvals.join(',\n') + opad + '}';
}else{
var keyvals=[],i=0;
for (var k in o) keyvals[i++] = [indent+opts.indent+JSON.stringify(k),o[k]];
if (opts.sorted) keyvals = keyvals.sort(function(kv1,kv2){ kv1=kv1[0]; kv2=kv2[0]; return kv1<kv2?-1:kv1>kv2?1:0 });
if (opts.aligned){
var longest = 0;
for (var i=keyvals.length;i--;) if (keyvals[i][0].length>longest) longest = keyvals[i][0].length;
var padding = repeat(' ',longest);
for (var i=keyvals.length;i--;) keyvals[i][0] = padRight(padding,keyvals[i][0]);
}
var indent2 = indent+opts.indent;
for (var i=keyvals.length;i--;){
var k=keyvals[i][0], v=keyvals[i][1];
var oneLine = k+colon+build(v,'');
keyvals[i] = (opts.wrap===false || oneLine.length<=opts.wrap || !v || typeof v!="object") ? oneLine : (k+colon+build(v,indent2).replace(/^\s+/,''));
}
return indent+'{\n'+keyvals.join(',\n')+'\n'+indent+'}'
}
default:
return indent+JSON.stringify(o);
}
}
}
function repeat(str,times){ // http://stackoverflow.com/a/17800645/405017
var result = '';
while(true){
if (times & 1) result += str;
times >>= 1;
if (times) str += str;
else break;
}
return result;
}
function padRight(pad, str){
return (str + pad).substring(0, pad.length);
}
}
neatJSON.version = "0.5";
})(typeof exports === 'undefined' ? this : exports);
Thanks a lot #all!
Based on the previous answers, here is another variant method providing custom replacement rules as parameter:
renderJSON : function(json, rr, code, pre){
if (typeof json !== 'string') {
json = JSON.stringify(json, undefined, '\t');
}
var rules = {
def : 'color:black;',
defKey : function(match){
return '<strong>' + match + '</strong>';
},
types : [
{
name : 'True',
regex : /true/,
type : 'boolean',
style : 'color:lightgreen;'
},
{
name : 'False',
regex : /false/,
type : 'boolean',
style : 'color:lightred;'
},
{
name : 'Unicode',
regex : /"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?/,
type : 'string',
style : 'color:green;'
},
{
name : 'Null',
regex : /null/,
type : 'nil',
style : 'color:magenta;'
},
{
name : 'Number',
regex : /-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/,
type : 'number',
style : 'color:darkorange;'
},
{
name : 'Whitespace',
regex : /\s+/,
type : 'whitespace',
style : function(match){
return '&nbsp';
}
}
],
keys : [
{
name : 'Testkey',
regex : /("testkey")/,
type : 'key',
style : function(match){
return '<h1>' + match + '</h1>';
}
}
],
punctuation : {
name : 'Punctuation',
regex : /([\,\.\}\{\[\]])/,
type : 'punctuation',
style : function(match){
return '<p>________</p>';
}
}
};
if('undefined' !== typeof jQuery){
rules = $.extend(rules, ('object' === typeof rr) ? rr : {});
}else{
for(var k in rr ){
rules[k] = rr[k];
}
}
var str = json.replace(/([\,\.\}\{\[\]]|"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var i = 0, p;
if (rules.punctuation.regex.test(match)) {
if('string' === typeof rules.punctuation.style){
return '<span style="'+ rules.punctuation.style + '">' + match + '</span>';
}else if('function' === typeof rules.punctuation.style){
return rules.punctuation.style(match);
} else{
return match;
}
}
if (/^"/.test(match)) {
if (/:$/.test(match)) {
for(i=0;i<rules.keys.length;i++){
p = rules.keys[i];
if (p.regex.test(match)) {
if('string' === typeof p.style){
return '<span style="'+ p.style + '">' + match + '</span>';
}else if('function' === typeof p.style){
return p.style(match);
} else{
return match;
}
}
}
return ('function'===typeof rules.defKey) ? rules.defKey(match) : '<span style="'+ rules.defKey + '">' + match + '</span>';
} else {
return ('function'===typeof rules.def) ? rules.def(match) : '<span style="'+ rules.def + '">' + match + '</span>';
}
} else {
for(i=0;i<rules.types.length;i++){
p = rules.types[i];
if (p.regex.test(match)) {
if('string' === typeof p.style){
return '<span style="'+ p.style + '">' + match + '</span>';
}else if('function' === typeof p.style){
return p.style(match);
} else{
return match;
}
}
}
}
});
if(true === pre)str = '<pre>' + str + '</pre>';
if(true === code)str = '<code>' + str + '</code>';
return str;
}
It works well:
console.table()
Read more here: https://developer.mozilla.org/pt-BR/docs/Web/API/Console/table
Here is a simple JSON format/color component written in React:
const HighlightedJSON = ({ json }: Object) => {
const highlightedJSON = jsonObj =>
Object.keys(jsonObj).map(key => {
const value = jsonObj[key];
let valueType = typeof value;
const isSimpleValue =
["string", "number", "boolean"].includes(valueType) || !value;
if (isSimpleValue && valueType === "object") {
valueType = "null";
}
return (
<div key={key} className="line">
<span className="key">{key}:</span>
{isSimpleValue ? (
<span className={valueType}>{`${value}`}</span>
) : (
highlightedJSON(value)
)}
</div>
);
});
return <div className="json">{highlightedJSON(json)}</div>;
};
See it working in this CodePen:
https://codepen.io/benshope/pen/BxVpjo
Hope that helps!
Couldn't find any solution that had good syntax highlighting for the console, so here's my 2p
Install & Add cli-highlight dependency
npm install cli-highlight --save
Define logjson globally
const highlight = require('cli-highlight').highlight
console.logjson = (obj) => console.log(
highlight( JSON.stringify(obj, null, 4),
{ language: 'json', ignoreIllegals: true } ));
Use
console.logjson({foo: "bar", someArray: ["string1", "string2"]});
I'd like to show my jsonAnalyze method here, it does a pretty print of the JSON structure only, but in some cases can be more usefull that printing the whole JSON.
Say you have a complex JSON like this:
let theJson = {
'username': 'elen',
'email': 'elen#test.com',
'state': 'married',
'profiles': [
{'name': 'elenLove', 'job': 'actor' },
{'name': 'elenDoe', 'job': 'spy'}
],
'hobbies': ['run', 'movies'],
'status': {
'home': {
'ownsHome': true,
'addresses': [
{'town': 'Mexico', 'address': '123 mexicoStr'},
{'town': 'Atlanta', 'address': '4B atlanta 45-48'},
]
},
'car': {
'ownsCar': true,
'cars': [
{'brand': 'Nissan', 'plate': 'TOKY-114', 'prevOwnersIDs': ['4532354531', '3454655344', '5566753422']},
{'brand': 'Benz', 'plate': 'ELEN-1225', 'prevOwnersIDs': ['4531124531', '97864655344', '887666753422']}
]
}
},
'active': true,
'employed': false,
};
Then the method will return the structure like this:
username
email
state
profiles[]
profiles[].name
profiles[].job
hobbies[]
status{}
status{}.home{}
status{}.home{}.ownsHome
status{}.home{}.addresses[]
status{}.home{}.addresses[].town
status{}.home{}.addresses[].address
status{}.car{}
status{}.car{}.ownsCar
status{}.car{}.cars[]
status{}.car{}.cars[].brand
status{}.car{}.cars[].plate
status{}.car{}.cars[].prevOwnersIDs[]
active
employed
So this is the jsonAnalyze() code:
function jsonAnalyze(obj) {
let arr = [];
analyzeJson(obj, null, arr);
return logBeautifiedDotNotation(arr);
function analyzeJson(obj, parentStr, outArr) {
let opt;
if (!outArr) {
return "no output array given"
}
for (let prop in obj) {
opt = parentStr ? parentStr + '.' + prop : prop;
if (Array.isArray(obj[prop]) && obj[prop] !== null) {
let arr = obj[prop];
if ((Array.isArray(arr[0]) || typeof arr[0] == "object") && arr[0] != null) {
outArr.push(opt + '[]');
analyzeJson(arr[0], opt + '[]', outArr);
} else {
outArr.push(opt + '[]');
}
} else if (typeof obj[prop] == "object" && obj[prop] !== null) {
outArr.push(opt + '{}');
analyzeJson(obj[prop], opt + '{}', outArr);
} else {
if (obj.hasOwnProperty(prop) && typeof obj[prop] != 'function') {
outArr.push(opt);
}
}
}
}
function logBeautifiedDotNotation(arr) {
retStr = '';
arr.map(function (item) {
let dotsAmount = item.split(".").length - 1;
let dotsString = Array(dotsAmount + 1).join(' ');
retStr += dotsString + item + '\n';
console.log(dotsString + item)
});
return retStr;
}
}
jsonAnalyze(theJson);
Douglas Crockford's JSON in JavaScript library will pretty print JSON via the stringify method.
You may also find the answers to this older question useful: How can I pretty-print JSON in (unix) shell script?
I ran into an issue today with #Pumbaa80's code. I'm trying to apply JSON syntax highlighting to data that I'm rendering in a Mithril view, so I need to create DOM nodes for everything in the JSON.stringify output.
I split the really long regex into its component parts as well.
render_json = (data) ->
# wraps JSON data in span elements so that syntax highlighting may be
# applied. Should be placed in a `whitespace: pre` context
if typeof(data) isnt 'string'
data = JSON.stringify(data, undefined, 2)
unicode = /"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?/
keyword = /\b(true|false|null)\b/
whitespace = /\s+/
punctuation = /[,.}{\[\]]/
number = /-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/
syntax = '(' + [unicode, keyword, whitespace,
punctuation, number].map((r) -> r.source).join('|') + ')'
parser = new RegExp(syntax, 'g')
nodes = data.match(parser) ? []
select_class = (node) ->
if punctuation.test(node)
return 'punctuation'
if /^\s+$/.test(node)
return 'whitespace'
if /^\"/.test(node)
if /:$/.test(node)
return 'key'
return 'string'
if /true|false/.test(node)
return 'boolean'
if /null/.test(node)
return 'null'
return 'number'
return nodes.map (node) ->
cls = select_class(node)
return Mithril('span', {class: cls}, node)
Code in context on Github here
If you're looking for a nice library to prettify json on a web page...
Prism.js is pretty good.
http://prismjs.com/
I found using JSON.stringify(obj, undefined, 2) to get the indentation, and then using prism to add a theme was a good approach.
If you're loading in JSON via an ajax call, then you can run one of Prism's utility methods to prettify
For example:
Prism.highlightAll()
Quick pretty human-readable JSON output in 1 line code (without colors):
document.documentElement.innerHTML='<pre>'+JSON.stringify(obj, null, 2)+'</pre>';
If you need this to work in a textarea the accepted solution will not work.
<textarea id='textarea'></textarea>
$("#textarea").append(formatJSON(JSON.stringify(jsonobject),true));
function formatJSON(json,textarea) {
var nl;
if(textarea) {
nl = "
";
} else {
nl = "<br>";
}
var tab = "    ";
var ret = "";
var numquotes = 0;
var betweenquotes = false;
var firstquote = false;
for (var i = 0; i < json.length; i++) {
var c = json[i];
if(c == '"') {
numquotes ++;
if((numquotes + 2) % 2 == 1) {
betweenquotes = true;
} else {
betweenquotes = false;
}
if((numquotes + 3) % 4 == 0) {
firstquote = true;
} else {
firstquote = false;
}
}
if(c == '[' && !betweenquotes) {
ret += c;
ret += nl;
continue;
}
if(c == '{' && !betweenquotes) {
ret += tab;
ret += c;
ret += nl;
continue;
}
if(c == '"' && firstquote) {
ret += tab + tab;
ret += c;
continue;
} else if (c == '"' && !firstquote) {
ret += c;
continue;
}
if(c == ',' && !betweenquotes) {
ret += c;
ret += nl;
continue;
}
if(c == '}' && !betweenquotes) {
ret += nl;
ret += tab;
ret += c;
continue;
}
if(c == ']' && !betweenquotes) {
ret += nl;
ret += c;
continue;
}
ret += c;
} // i loop
return ret;
}
This is nice:
https://github.com/mafintosh/json-markup from mafintosh
const jsonMarkup = require('json-markup')
const html = jsonMarkup({hello:'world'})
document.querySelector('#myElem').innerHTML = html
HTML
<link ref="stylesheet" href="style.css">
<div id="myElem></div>
Example stylesheet can be found here
https://raw.githubusercontent.com/mafintosh/json-markup/master/style.css
To highlight and beautify it in HTML using Bootstrap:
function prettifyJson(json, prettify) {
if (typeof json !== 'string') {
if (prettify) {
json = JSON.stringify(json, undefined, 4);
} else {
json = JSON.stringify(json);
}
}
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
function(match) {
let cls = "<span>";
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = "<span class='text-danger'>";
} else {
cls = "<span>";
}
} else if (/true|false/.test(match)) {
cls = "<span class='text-primary'>";
} else if (/null/.test(match)) {
cls = "<span class='text-info'>";
}
return cls + match + "</span>";
}
);
}
based on #user123444555621, just slightly more modern.
const clsMap = [
[/^".*:$/, "key"],
[/^"/, "string"],
[/true|false/, "boolean"],
[/null/, "key"],
[/.*/, "number"],
]
const syntaxHighlight = obj => JSON.stringify(obj, null, 4)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => `<span class="${clsMap.find(([regex]) => regex.test(match))[1]}">${match}</span>`);
you can also specify the colors inside js (no CSS needed)
const clsMap = [
[/^".*:$/, "red"],
[/^"/, "green"],
[/true|false/, "blue"],
[/null/, "magenta"],
[/.*/, "darkorange"],
]
const syntaxHighlight = obj => JSON.stringify(obj, null, 4)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => `<span style="color:${clsMap.find(([regex]) => regex.test(match))[1]}">${match}</span>`);
and a version with less regex
const clsMap = [
[match => match.startsWith('"') && match.endsWith(':'), "red"],
[match => match.startsWith('"'), "green"],
[match => match === "true" || match === "false" , "blue"],
[match => match === "null", "magenta"],
[() => true, "darkorange"],
];
const syntaxHighlight = obj => JSON.stringify(obj, null, 4)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => `<span style="color:${clsMap.find(([fn]) => fn(match))[1]}">${match}</span>`);
it's for Laravel, Codeigniter
Html:
<pre class="jsonPre"> </pre>
Controller: Return the JSON value from the controller as like as
return json_encode($data, JSON_PRETTY_PRINT);
In script:
<script> $('.jsonPre').html(result); </script>
result will be
Here is how you can print without using native function.
function pretty(ob, lvl = 0) {
let temp = [];
if(typeof ob === "object"){
for(let x in ob) {
if(ob.hasOwnProperty(x)) {
temp.push( getTabs(lvl+1) + x + ":" + pretty(ob[x], lvl+1) );
}
}
return "{\n"+ temp.join(",\n") +"\n" + getTabs(lvl) + "}";
}
else {
return ob;
}
}
function getTabs(n) {
let c = 0, res = "";
while(c++ < n)
res+="\t";
return res;
}
let obj = {a: {b: 2}, x: {y: 3}};
console.log(pretty(obj));
/*
{
a: {
b: 2
},
x: {
y: 3
}
}
*/
The simplest way to display an object for debugging purposes:
console.log("data",data) // lets you unfold the object manually
If you want to display the object in the DOM, you should consider that it could contain strings that would be interpreted as HTML. Therefore, you need to do some escaping...
var s = JSON.stringify(data,null,2) // format
var e = new Option(s).innerHTML // escape
document.body.insertAdjacentHTML('beforeend','<pre>'+e+'</pre>') // display
<!-- here is a complete example pretty print with more space between lines-->
<!-- be sure to pass a json string not a json object -->
<!-- use line-height to increase or decrease spacing between json lines -->
<style type="text/css">
.preJsonTxt{
font-size: 18px;
text-overflow: ellipsis;
overflow: hidden;
line-height: 200%;
}
.boxedIn{
border: 1px solid black;
margin: 20px;
padding: 20px;
}
</style>
<div class="boxedIn">
<h3>Configuration Parameters</h3>
<pre id="jsonCfgParams" class="preJsonTxt">{{ cfgParams }}</pre>
</div>
<script language="JavaScript">
$( document ).ready(function()
{
$(formatJson);
<!-- this will do a pretty print on the json cfg params -->
function formatJson() {
var element = $("#jsonCfgParams");
var obj = JSON.parse(element.text());
element.html(JSON.stringify(obj, undefined, 2));
}
});
</script>

Making JSON output "pretty" with CSS [duplicate]

How can I display JSON in an easy-to-read (for human readers) format? I'm looking primarily for indentation and whitespace, with perhaps even colors / font-styles / etc.
Pretty-printing is implemented natively in JSON.stringify(). The third argument enables pretty printing and sets the spacing to use:
var str = JSON.stringify(obj, null, 2); // spacing level = 2
If you need syntax highlighting, you might use some regex magic like so:
function syntaxHighlight(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
See in action here: jsfiddle
Or a full snippet provided below:
function output(inp) {
document.body.appendChild(document.createElement('pre')).innerHTML = inp;
}
function syntaxHighlight(json) {
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
var obj = {a:1, 'b':'foo', c:[false,'false',null, 'null', {d:{e:1.3e5,f:'1.3e5'}}]};
var str = JSON.stringify(obj, undefined, 4);
output(str);
output(syntaxHighlight(str));
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
.null { color: magenta; }
.key { color: red; }
User Pumbaa80's answer is great if you have an object you want pretty printed. If you're starting from a valid JSON string that you want to pretty printed, you need to convert it to an object first:
var jsonString = '{"some":"json"}';
var jsonPretty = JSON.stringify(JSON.parse(jsonString),null,2);
This builds a JSON object from the string, and then converts it back to a string using JSON stringify's pretty print.
Better way.
Prettify JSON Array in Javascript
JSON.stringify(jsonobj,null,'\t')
var jsonObj = {"streetLabel": "Avenue Anatole France", "city": "Paris 07", "postalCode": "75007", "countryCode": "FRA", "countryLabel": "France" };
document.getElementById("result-before").innerHTML = JSON.stringify(jsonObj);
In case of displaying in HTML, you should to add a balise <pre></pre>
document.getElementById("result-after").innerHTML = "<pre>"+JSON.stringify(jsonObj,undefined, 2) +"</pre>"
Example:
var jsonObj = {"streetLabel": "Avenue Anatole France", "city": "Paris 07", "postalCode": "75007", "countryCode": "FRA", "countryLabel": "France" };
document.getElementById("result-before").innerHTML = JSON.stringify(jsonObj);
document.getElementById("result-after").innerHTML = "<pre>"+JSON.stringify(jsonObj,undefined, 2) +"</pre>"
div { float:left; clear:both; margin: 1em 0; }
<div id="result-before"></div>
<div id="result-after"></div>
Based on Pumbaa80's answer I have modified the code to use the console.log colours (working on Chrome for sure) and not HTML. Output can be seen inside console. You can edit the _variables inside the function adding some more styling.
function JSONstringify(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, '\t');
}
var
arr = [],
_string = 'color:green',
_number = 'color:darkorange',
_boolean = 'color:blue',
_null = 'color:magenta',
_key = 'color:red';
json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var style = _number;
if (/^"/.test(match)) {
if (/:$/.test(match)) {
style = _key;
} else {
style = _string;
}
} else if (/true|false/.test(match)) {
style = _boolean;
} else if (/null/.test(match)) {
style = _null;
}
arr.push(style);
arr.push('');
return '%c' + match + '%c';
});
arr.unshift(json);
console.log.apply(console, arr);
}
Here is a bookmarklet you can use:
javascript:function JSONstringify(json) {if (typeof json != 'string') {json = JSON.stringify(json, undefined, '\t');}var arr = [],_string = 'color:green',_number = 'color:darkorange',_boolean = 'color:blue',_null = 'color:magenta',_key = 'color:red';json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {var style = _number;if (/^"/.test(match)) {if (/:$/.test(match)) {style = _key;} else {style = _string;}} else if (/true|false/.test(match)) {style = _boolean;} else if (/null/.test(match)) {style = _null;}arr.push(style);arr.push('');return '%c' + match + '%c';});arr.unshift(json);console.log.apply(console, arr);};void(0);
Usage:
var obj = {a:1, 'b':'foo', c:[false,null, {d:{e:1.3e5}}]};
JSONstringify(obj);
Edit: I just tried to escape the % symbol with this line, after the variables declaration:
json = json.replace(/%/g, '%%');
But I find out that Chrome is not supporting % escaping in the console. Strange... Maybe this will work in the future.
Cheers!
I think you're looking for something like this :
JSON.stringify(obj, null, '\t');
This "pretty-prints" your JSON string, using a tab for indentation.
If you prefer to use spaces instead of tabs, you could also use a number for the number of spaces you'd like :
JSON.stringify(obj, null, 2);
You can use console.dir(), which is a shortcut for console.log(util.inspect()).
(The only difference is that it bypasses any custom inspect() function defined on an object.)
It uses syntax-highlighting, smart indentation, removes quotes from keys and just makes the output as pretty as it gets.
const object = JSON.parse(jsonString)
console.dir(object, {depth: null, colors: true})
and for the command line:
cat package.json | node -e "process.stdin.pipe(new stream.Writable({write: chunk => console.dir(JSON.parse(chunk), {depth: null, colors: true})}))"
I use the JSONView Chrome extension (it is as pretty as it gets :):
Edit: added jsonreport.js
I've also released an online stand-alone JSON pretty print viewer, jsonreport.js, that provides a human readable HTML5 report you can use to view any JSON data.
You can read more about the format in New JavaScript HTML5 Report Format.
If you are using ES5, simply call JSON.stringify with:
2nd arg: replacer; set to null,
3rd arg: space; use tab.
JSON.stringify(anObject, null, '\t');
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Here's user123444555621's awesome HTML one adapted for terminals. Handy for debugging Node scripts:
function prettyJ(json) {
if (typeof json !== 'string') {
json = JSON.stringify(json, undefined, 2);
}
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
function (match) {
let cls = "\x1b[36m";
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = "\x1b[34m";
} else {
cls = "\x1b[32m";
}
} else if (/true|false/.test(match)) {
cls = "\x1b[35m";
} else if (/null/.test(match)) {
cls = "\x1b[31m";
}
return cls + match + "\x1b[0m";
}
);
}
Usage:
// thing = any json OR string of json
prettyJ(thing);
For debugging purpose I use:
console.debug("%o", data);
https://getfirebug.com/wiki/index.php/Console_API
https://developer.mozilla.org/en-US/docs/DOM/console
You can use JSON.stringify(your object, null, 2)
The second parameter can be used as a replacer function which takes key and Val as parameters.This can be used in case you want to modify something within your JSON object.
more reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Unsatisfied with other pretty printers for Ruby, I wrote my own (NeatJSON) and then ported it to JavaScript including a free online formatter. The code is free under MIT license (quite permissive).
Features (all optional):
Set a line width and wrap in a way that keeps objects and arrays on the same line when they fit, wrapping one value per line when they don't.
Sort object keys if you like.
Align object keys (line up the colons).
Format floating point numbers to specific number of decimals, without messing up the integers.
'Short' wrapping mode puts opening and closing brackets/braces on the same line as values, providing a format that some prefer.
Granular control over spacing for arrays and objects, between brackets, before/after colons and commas.
Function is made available to both web browsers and Node.js.
I'll copy the source code here so that this is not just a link to a library, but I encourage you to go to the GitHub project page, as that will be kept up-to-date and the code below will not.
(function(exports){
exports.neatJSON = neatJSON;
function neatJSON(value,opts){
opts = opts || {}
if (!('wrap' in opts)) opts.wrap = 80;
if (opts.wrap==true) opts.wrap = -1;
if (!('indent' in opts)) opts.indent = ' ';
if (!('arrayPadding' in opts)) opts.arrayPadding = ('padding' in opts) ? opts.padding : 0;
if (!('objectPadding' in opts)) opts.objectPadding = ('padding' in opts) ? opts.padding : 0;
if (!('afterComma' in opts)) opts.afterComma = ('aroundComma' in opts) ? opts.aroundComma : 0;
if (!('beforeComma' in opts)) opts.beforeComma = ('aroundComma' in opts) ? opts.aroundComma : 0;
if (!('afterColon' in opts)) opts.afterColon = ('aroundColon' in opts) ? opts.aroundColon : 0;
if (!('beforeColon' in opts)) opts.beforeColon = ('aroundColon' in opts) ? opts.aroundColon : 0;
var apad = repeat(' ',opts.arrayPadding),
opad = repeat(' ',opts.objectPadding),
comma = repeat(' ',opts.beforeComma)+','+repeat(' ',opts.afterComma),
colon = repeat(' ',opts.beforeColon)+':'+repeat(' ',opts.afterColon);
return build(value,'');
function build(o,indent){
if (o===null || o===undefined) return indent+'null';
else{
switch(o.constructor){
case Number:
var isFloat = (o === +o && o !== (o|0));
return indent + ((isFloat && ('decimals' in opts)) ? o.toFixed(opts.decimals) : (o+''));
case Array:
var pieces = o.map(function(v){ return build(v,'') });
var oneLine = indent+'['+apad+pieces.join(comma)+apad+']';
if (opts.wrap===false || oneLine.length<=opts.wrap) return oneLine;
if (opts.short){
var indent2 = indent+' '+apad;
pieces = o.map(function(v){ return build(v,indent2) });
pieces[0] = pieces[0].replace(indent2,indent+'['+apad);
pieces[pieces.length-1] = pieces[pieces.length-1]+apad+']';
return pieces.join(',\n');
}else{
var indent2 = indent+opts.indent;
return indent+'[\n'+o.map(function(v){ return build(v,indent2) }).join(',\n')+'\n'+indent+']';
}
case Object:
var keyvals=[],i=0;
for (var k in o) keyvals[i++] = [JSON.stringify(k), build(o[k],'')];
if (opts.sorted) keyvals = keyvals.sort(function(kv1,kv2){ kv1=kv1[0]; kv2=kv2[0]; return kv1<kv2?-1:kv1>kv2?1:0 });
keyvals = keyvals.map(function(kv){ return kv.join(colon) }).join(comma);
var oneLine = indent+"{"+opad+keyvals+opad+"}";
if (opts.wrap===false || oneLine.length<opts.wrap) return oneLine;
if (opts.short){
var keyvals=[],i=0;
for (var k in o) keyvals[i++] = [indent+' '+opad+JSON.stringify(k),o[k]];
if (opts.sorted) keyvals = keyvals.sort(function(kv1,kv2){ kv1=kv1[0]; kv2=kv2[0]; return kv1<kv2?-1:kv1>kv2?1:0 });
keyvals[0][0] = keyvals[0][0].replace(indent+' ',indent+'{');
if (opts.aligned){
var longest = 0;
for (var i=keyvals.length;i--;) if (keyvals[i][0].length>longest) longest = keyvals[i][0].length;
var padding = repeat(' ',longest);
for (var i=keyvals.length;i--;) keyvals[i][0] = padRight(padding,keyvals[i][0]);
}
for (var i=keyvals.length;i--;){
var k=keyvals[i][0], v=keyvals[i][1];
var indent2 = repeat(' ',(k+colon).length);
var oneLine = k+colon+build(v,'');
keyvals[i] = (opts.wrap===false || oneLine.length<=opts.wrap || !v || typeof v!="object") ? oneLine : (k+colon+build(v,indent2).replace(/^\s+/,''));
}
return keyvals.join(',\n') + opad + '}';
}else{
var keyvals=[],i=0;
for (var k in o) keyvals[i++] = [indent+opts.indent+JSON.stringify(k),o[k]];
if (opts.sorted) keyvals = keyvals.sort(function(kv1,kv2){ kv1=kv1[0]; kv2=kv2[0]; return kv1<kv2?-1:kv1>kv2?1:0 });
if (opts.aligned){
var longest = 0;
for (var i=keyvals.length;i--;) if (keyvals[i][0].length>longest) longest = keyvals[i][0].length;
var padding = repeat(' ',longest);
for (var i=keyvals.length;i--;) keyvals[i][0] = padRight(padding,keyvals[i][0]);
}
var indent2 = indent+opts.indent;
for (var i=keyvals.length;i--;){
var k=keyvals[i][0], v=keyvals[i][1];
var oneLine = k+colon+build(v,'');
keyvals[i] = (opts.wrap===false || oneLine.length<=opts.wrap || !v || typeof v!="object") ? oneLine : (k+colon+build(v,indent2).replace(/^\s+/,''));
}
return indent+'{\n'+keyvals.join(',\n')+'\n'+indent+'}'
}
default:
return indent+JSON.stringify(o);
}
}
}
function repeat(str,times){ // http://stackoverflow.com/a/17800645/405017
var result = '';
while(true){
if (times & 1) result += str;
times >>= 1;
if (times) str += str;
else break;
}
return result;
}
function padRight(pad, str){
return (str + pad).substring(0, pad.length);
}
}
neatJSON.version = "0.5";
})(typeof exports === 'undefined' ? this : exports);
Thanks a lot #all!
Based on the previous answers, here is another variant method providing custom replacement rules as parameter:
renderJSON : function(json, rr, code, pre){
if (typeof json !== 'string') {
json = JSON.stringify(json, undefined, '\t');
}
var rules = {
def : 'color:black;',
defKey : function(match){
return '<strong>' + match + '</strong>';
},
types : [
{
name : 'True',
regex : /true/,
type : 'boolean',
style : 'color:lightgreen;'
},
{
name : 'False',
regex : /false/,
type : 'boolean',
style : 'color:lightred;'
},
{
name : 'Unicode',
regex : /"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?/,
type : 'string',
style : 'color:green;'
},
{
name : 'Null',
regex : /null/,
type : 'nil',
style : 'color:magenta;'
},
{
name : 'Number',
regex : /-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/,
type : 'number',
style : 'color:darkorange;'
},
{
name : 'Whitespace',
regex : /\s+/,
type : 'whitespace',
style : function(match){
return '&nbsp';
}
}
],
keys : [
{
name : 'Testkey',
regex : /("testkey")/,
type : 'key',
style : function(match){
return '<h1>' + match + '</h1>';
}
}
],
punctuation : {
name : 'Punctuation',
regex : /([\,\.\}\{\[\]])/,
type : 'punctuation',
style : function(match){
return '<p>________</p>';
}
}
};
if('undefined' !== typeof jQuery){
rules = $.extend(rules, ('object' === typeof rr) ? rr : {});
}else{
for(var k in rr ){
rules[k] = rr[k];
}
}
var str = json.replace(/([\,\.\}\{\[\]]|"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var i = 0, p;
if (rules.punctuation.regex.test(match)) {
if('string' === typeof rules.punctuation.style){
return '<span style="'+ rules.punctuation.style + '">' + match + '</span>';
}else if('function' === typeof rules.punctuation.style){
return rules.punctuation.style(match);
} else{
return match;
}
}
if (/^"/.test(match)) {
if (/:$/.test(match)) {
for(i=0;i<rules.keys.length;i++){
p = rules.keys[i];
if (p.regex.test(match)) {
if('string' === typeof p.style){
return '<span style="'+ p.style + '">' + match + '</span>';
}else if('function' === typeof p.style){
return p.style(match);
} else{
return match;
}
}
}
return ('function'===typeof rules.defKey) ? rules.defKey(match) : '<span style="'+ rules.defKey + '">' + match + '</span>';
} else {
return ('function'===typeof rules.def) ? rules.def(match) : '<span style="'+ rules.def + '">' + match + '</span>';
}
} else {
for(i=0;i<rules.types.length;i++){
p = rules.types[i];
if (p.regex.test(match)) {
if('string' === typeof p.style){
return '<span style="'+ p.style + '">' + match + '</span>';
}else if('function' === typeof p.style){
return p.style(match);
} else{
return match;
}
}
}
}
});
if(true === pre)str = '<pre>' + str + '</pre>';
if(true === code)str = '<code>' + str + '</code>';
return str;
}
It works well:
console.table()
Read more here: https://developer.mozilla.org/pt-BR/docs/Web/API/Console/table
Here is a simple JSON format/color component written in React:
const HighlightedJSON = ({ json }: Object) => {
const highlightedJSON = jsonObj =>
Object.keys(jsonObj).map(key => {
const value = jsonObj[key];
let valueType = typeof value;
const isSimpleValue =
["string", "number", "boolean"].includes(valueType) || !value;
if (isSimpleValue && valueType === "object") {
valueType = "null";
}
return (
<div key={key} className="line">
<span className="key">{key}:</span>
{isSimpleValue ? (
<span className={valueType}>{`${value}`}</span>
) : (
highlightedJSON(value)
)}
</div>
);
});
return <div className="json">{highlightedJSON(json)}</div>;
};
See it working in this CodePen:
https://codepen.io/benshope/pen/BxVpjo
Hope that helps!
Couldn't find any solution that had good syntax highlighting for the console, so here's my 2p
Install & Add cli-highlight dependency
npm install cli-highlight --save
Define logjson globally
const highlight = require('cli-highlight').highlight
console.logjson = (obj) => console.log(
highlight( JSON.stringify(obj, null, 4),
{ language: 'json', ignoreIllegals: true } ));
Use
console.logjson({foo: "bar", someArray: ["string1", "string2"]});
I'd like to show my jsonAnalyze method here, it does a pretty print of the JSON structure only, but in some cases can be more usefull that printing the whole JSON.
Say you have a complex JSON like this:
let theJson = {
'username': 'elen',
'email': 'elen#test.com',
'state': 'married',
'profiles': [
{'name': 'elenLove', 'job': 'actor' },
{'name': 'elenDoe', 'job': 'spy'}
],
'hobbies': ['run', 'movies'],
'status': {
'home': {
'ownsHome': true,
'addresses': [
{'town': 'Mexico', 'address': '123 mexicoStr'},
{'town': 'Atlanta', 'address': '4B atlanta 45-48'},
]
},
'car': {
'ownsCar': true,
'cars': [
{'brand': 'Nissan', 'plate': 'TOKY-114', 'prevOwnersIDs': ['4532354531', '3454655344', '5566753422']},
{'brand': 'Benz', 'plate': 'ELEN-1225', 'prevOwnersIDs': ['4531124531', '97864655344', '887666753422']}
]
}
},
'active': true,
'employed': false,
};
Then the method will return the structure like this:
username
email
state
profiles[]
profiles[].name
profiles[].job
hobbies[]
status{}
status{}.home{}
status{}.home{}.ownsHome
status{}.home{}.addresses[]
status{}.home{}.addresses[].town
status{}.home{}.addresses[].address
status{}.car{}
status{}.car{}.ownsCar
status{}.car{}.cars[]
status{}.car{}.cars[].brand
status{}.car{}.cars[].plate
status{}.car{}.cars[].prevOwnersIDs[]
active
employed
So this is the jsonAnalyze() code:
function jsonAnalyze(obj) {
let arr = [];
analyzeJson(obj, null, arr);
return logBeautifiedDotNotation(arr);
function analyzeJson(obj, parentStr, outArr) {
let opt;
if (!outArr) {
return "no output array given"
}
for (let prop in obj) {
opt = parentStr ? parentStr + '.' + prop : prop;
if (Array.isArray(obj[prop]) && obj[prop] !== null) {
let arr = obj[prop];
if ((Array.isArray(arr[0]) || typeof arr[0] == "object") && arr[0] != null) {
outArr.push(opt + '[]');
analyzeJson(arr[0], opt + '[]', outArr);
} else {
outArr.push(opt + '[]');
}
} else if (typeof obj[prop] == "object" && obj[prop] !== null) {
outArr.push(opt + '{}');
analyzeJson(obj[prop], opt + '{}', outArr);
} else {
if (obj.hasOwnProperty(prop) && typeof obj[prop] != 'function') {
outArr.push(opt);
}
}
}
}
function logBeautifiedDotNotation(arr) {
retStr = '';
arr.map(function (item) {
let dotsAmount = item.split(".").length - 1;
let dotsString = Array(dotsAmount + 1).join(' ');
retStr += dotsString + item + '\n';
console.log(dotsString + item)
});
return retStr;
}
}
jsonAnalyze(theJson);
Douglas Crockford's JSON in JavaScript library will pretty print JSON via the stringify method.
You may also find the answers to this older question useful: How can I pretty-print JSON in (unix) shell script?
I ran into an issue today with #Pumbaa80's code. I'm trying to apply JSON syntax highlighting to data that I'm rendering in a Mithril view, so I need to create DOM nodes for everything in the JSON.stringify output.
I split the really long regex into its component parts as well.
render_json = (data) ->
# wraps JSON data in span elements so that syntax highlighting may be
# applied. Should be placed in a `whitespace: pre` context
if typeof(data) isnt 'string'
data = JSON.stringify(data, undefined, 2)
unicode = /"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?/
keyword = /\b(true|false|null)\b/
whitespace = /\s+/
punctuation = /[,.}{\[\]]/
number = /-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/
syntax = '(' + [unicode, keyword, whitespace,
punctuation, number].map((r) -> r.source).join('|') + ')'
parser = new RegExp(syntax, 'g')
nodes = data.match(parser) ? []
select_class = (node) ->
if punctuation.test(node)
return 'punctuation'
if /^\s+$/.test(node)
return 'whitespace'
if /^\"/.test(node)
if /:$/.test(node)
return 'key'
return 'string'
if /true|false/.test(node)
return 'boolean'
if /null/.test(node)
return 'null'
return 'number'
return nodes.map (node) ->
cls = select_class(node)
return Mithril('span', {class: cls}, node)
Code in context on Github here
If you're looking for a nice library to prettify json on a web page...
Prism.js is pretty good.
http://prismjs.com/
I found using JSON.stringify(obj, undefined, 2) to get the indentation, and then using prism to add a theme was a good approach.
If you're loading in JSON via an ajax call, then you can run one of Prism's utility methods to prettify
For example:
Prism.highlightAll()
Quick pretty human-readable JSON output in 1 line code (without colors):
document.documentElement.innerHTML='<pre>'+JSON.stringify(obj, null, 2)+'</pre>';
If you need this to work in a textarea the accepted solution will not work.
<textarea id='textarea'></textarea>
$("#textarea").append(formatJSON(JSON.stringify(jsonobject),true));
function formatJSON(json,textarea) {
var nl;
if(textarea) {
nl = "
";
} else {
nl = "<br>";
}
var tab = "    ";
var ret = "";
var numquotes = 0;
var betweenquotes = false;
var firstquote = false;
for (var i = 0; i < json.length; i++) {
var c = json[i];
if(c == '"') {
numquotes ++;
if((numquotes + 2) % 2 == 1) {
betweenquotes = true;
} else {
betweenquotes = false;
}
if((numquotes + 3) % 4 == 0) {
firstquote = true;
} else {
firstquote = false;
}
}
if(c == '[' && !betweenquotes) {
ret += c;
ret += nl;
continue;
}
if(c == '{' && !betweenquotes) {
ret += tab;
ret += c;
ret += nl;
continue;
}
if(c == '"' && firstquote) {
ret += tab + tab;
ret += c;
continue;
} else if (c == '"' && !firstquote) {
ret += c;
continue;
}
if(c == ',' && !betweenquotes) {
ret += c;
ret += nl;
continue;
}
if(c == '}' && !betweenquotes) {
ret += nl;
ret += tab;
ret += c;
continue;
}
if(c == ']' && !betweenquotes) {
ret += nl;
ret += c;
continue;
}
ret += c;
} // i loop
return ret;
}
This is nice:
https://github.com/mafintosh/json-markup from mafintosh
const jsonMarkup = require('json-markup')
const html = jsonMarkup({hello:'world'})
document.querySelector('#myElem').innerHTML = html
HTML
<link ref="stylesheet" href="style.css">
<div id="myElem></div>
Example stylesheet can be found here
https://raw.githubusercontent.com/mafintosh/json-markup/master/style.css
To highlight and beautify it in HTML using Bootstrap:
function prettifyJson(json, prettify) {
if (typeof json !== 'string') {
if (prettify) {
json = JSON.stringify(json, undefined, 4);
} else {
json = JSON.stringify(json);
}
}
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
function(match) {
let cls = "<span>";
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = "<span class='text-danger'>";
} else {
cls = "<span>";
}
} else if (/true|false/.test(match)) {
cls = "<span class='text-primary'>";
} else if (/null/.test(match)) {
cls = "<span class='text-info'>";
}
return cls + match + "</span>";
}
);
}
based on #user123444555621, just slightly more modern.
const clsMap = [
[/^".*:$/, "key"],
[/^"/, "string"],
[/true|false/, "boolean"],
[/null/, "key"],
[/.*/, "number"],
]
const syntaxHighlight = obj => JSON.stringify(obj, null, 4)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => `<span class="${clsMap.find(([regex]) => regex.test(match))[1]}">${match}</span>`);
you can also specify the colors inside js (no CSS needed)
const clsMap = [
[/^".*:$/, "red"],
[/^"/, "green"],
[/true|false/, "blue"],
[/null/, "magenta"],
[/.*/, "darkorange"],
]
const syntaxHighlight = obj => JSON.stringify(obj, null, 4)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => `<span style="color:${clsMap.find(([regex]) => regex.test(match))[1]}">${match}</span>`);
and a version with less regex
const clsMap = [
[match => match.startsWith('"') && match.endsWith(':'), "red"],
[match => match.startsWith('"'), "green"],
[match => match === "true" || match === "false" , "blue"],
[match => match === "null", "magenta"],
[() => true, "darkorange"],
];
const syntaxHighlight = obj => JSON.stringify(obj, null, 4)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => `<span style="color:${clsMap.find(([fn]) => fn(match))[1]}">${match}</span>`);
it's for Laravel, Codeigniter
Html:
<pre class="jsonPre"> </pre>
Controller: Return the JSON value from the controller as like as
return json_encode($data, JSON_PRETTY_PRINT);
In script:
<script> $('.jsonPre').html(result); </script>
result will be
Here is how you can print without using native function.
function pretty(ob, lvl = 0) {
let temp = [];
if(typeof ob === "object"){
for(let x in ob) {
if(ob.hasOwnProperty(x)) {
temp.push( getTabs(lvl+1) + x + ":" + pretty(ob[x], lvl+1) );
}
}
return "{\n"+ temp.join(",\n") +"\n" + getTabs(lvl) + "}";
}
else {
return ob;
}
}
function getTabs(n) {
let c = 0, res = "";
while(c++ < n)
res+="\t";
return res;
}
let obj = {a: {b: 2}, x: {y: 3}};
console.log(pretty(obj));
/*
{
a: {
b: 2
},
x: {
y: 3
}
}
*/
The simplest way to display an object for debugging purposes:
console.log("data",data) // lets you unfold the object manually
If you want to display the object in the DOM, you should consider that it could contain strings that would be interpreted as HTML. Therefore, you need to do some escaping...
var s = JSON.stringify(data,null,2) // format
var e = new Option(s).innerHTML // escape
document.body.insertAdjacentHTML('beforeend','<pre>'+e+'</pre>') // display
<!-- here is a complete example pretty print with more space between lines-->
<!-- be sure to pass a json string not a json object -->
<!-- use line-height to increase or decrease spacing between json lines -->
<style type="text/css">
.preJsonTxt{
font-size: 18px;
text-overflow: ellipsis;
overflow: hidden;
line-height: 200%;
}
.boxedIn{
border: 1px solid black;
margin: 20px;
padding: 20px;
}
</style>
<div class="boxedIn">
<h3>Configuration Parameters</h3>
<pre id="jsonCfgParams" class="preJsonTxt">{{ cfgParams }}</pre>
</div>
<script language="JavaScript">
$( document ).ready(function()
{
$(formatJson);
<!-- this will do a pretty print on the json cfg params -->
function formatJson() {
var element = $("#jsonCfgParams");
var obj = JSON.parse(element.text());
element.html(JSON.stringify(obj, undefined, 2));
}
});
</script>

Autocompleting XML values and attributes in Ace editor

I'm looking to autocomplete XML tags and attributes. The valid values will come from the server. For example,
If I have a tag such as,
<status></status>
and my cursor is inside the open and closing tags, I'd like to hit control + space and have only valid values appear in the drop-down. Such as: ok, error, warning, ...
Similarly for attributes,
<status audience="">ok</status>
If my cursor has focus inside the quotes I'd like only valid audiences to appear in the drop-down when hitting control + space.
Here's what I have so far. This completer completes words I'm typing. I just can't figure out how to know what kind of tag I'm inside and how to send specific values for that tag or attribute.
Any ideas or examples to point me to? Thanks, /w
function loadEditor() {
var langTools = ace.require("ace/ext/language_tools");
editor = ace.edit("editor");
editor.setOptions({
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: true,
});
editor.getSession().setMode("ace/mode/xml");
var myCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {
callback(null, []);
return;
}
$.getJSON("completions.php?a=completions&prefix="
+ prefix + "&content=" + session, function(json) {
callback(null, json.map(function(c) {
console.log("value: " + c.value);
return {value: c.value, caption: c.caption, meta: c.meta, score:c.score};
}));
})
}
};
langTools.addCompleter(myCompleter);
}
So far I haven't been able to find any projects with XML completion, so this is what I have implemented.
The XhtmlTagInterpreter has one function getCompleteInfo() that returns a JavaScript object of the form {completeType: "attribute", tagName: "feline", attributeName: "breed"}. In this example it would try to auto-complete the breed attribute of <feline breed="" />.
It sends that data to the server for the appropriate breed values. This service is up to you to implement. e.g. https://www.example.com/services/mock/autocompleter/attribute.json?tagName=feline&attributeName=breed
The JSON returned will be something like this.
[
{"score":"1000","meta":"cats","caption":"siamese","value":"siamese"},
{"score":"1000","meta":"cats","caption":"burmese","value":"burmese"},
{"score":"1000","meta":"cats","caption":"bengal","value":"bengal"}
]
Here is the working JavaScript.
function XHtmlTagInterpreter(row, col, session) {
"use strict";
this.row = row;
this.col = col;
this.session = session;
this.leftOfCursor = null;
this.rightOfCursor = null;
this.leftType = null;
this.rightType = null;
}
/**
* Sets the left of cursor property used by other methods. This is a
* string without new lines from the beginning of the document to the
* letter just before the cursor.
*/
XHtmlTagInterpreter.prototype.setLeftOfCursor = function() {
"use strict";
this.leftOfCursor = "";
for (var r=0; r<=this.row; r++) {
if (r === this.row) {
var line = this.session.getLine(r);
for (var c=0; c<this.col; c++) {
this.leftOfCursor += line[c];
}
} else {
this.leftOfCursor += this.session.getLine(r);
}
}
};
/**
* Sets the right of cursor property used by other methods. This is a
* string without new lines from the letter just to the right of the cursor
* to the end of the document.
*/
XHtmlTagInterpreter.prototype.setRightOfCursor = function() {
"use strict";
this.rightOfCursor = "";
for (var r=this.row; r<=this.session.getLength(); r++) {
if (r === this.row) {
var line = this.session.getLine(r);
for (var c=this.col; c<line.length; c++) {
this.rightOfCursor += line[c];
}
} else {
this.rightOfCursor += this.session.getLine(r);
}
}
};
/**
* Sets the left type depending on first non-whitespace character to the
* left of the cursor position. We look for a right angle or a quotation.
* If a right angle we assume the cursor is inside a tag. If quotation the
* cursor is inside an attribute. We set the left type value to 'value'
* or 'attribute'.
*/
XHtmlTagInterpreter.prototype.setLeftType = function() {
"use strict";
this.setLeftOfCursor();
if (this.leftOfCursor === undefined || this.leftOfCursor.length === 0) {
this.leftType = "";
return;
}
for (var i=this.leftOfCursor.length-1; i>=0; i--) {
if (this.leftOfCursor[i] === " " || this.leftOfCursor[i] === "\t") {
continue;
}
if (this.leftOfCursor[i] === ">") {
this.leftType = "value";
return;
} else if (this.leftOfCursor[i] === '"') {
this.leftType = "attribute";
return;
} else {
this.leftType = "";
return;
}
}
};
/**
* Sets the right type depending on first non-whitespace character to the
* right of the cursor position. We look for a left angle or a quotation.
* If a left angle we assume the cursor is inside a tag. If quotation the
* cursor is inside an attribute. We set the right type value to 'value'
* or 'attribute'.
*/
XHtmlTagInterpreter.prototype.setRightType = function() {
"use strict";
this.setRightOfCursor();
if (this.rightOfCursor === undefined
|| this.rightOfCursor.length === 0) {
this.rightType = "";
return;
}
for (var i=0; i<this.rightOfCursor.length; i++) {
if (this.rightOfCursor[i] === " "
|| this.rightOfCursor[i] === "\t") {
continue;
}
if (this.rightOfCursor[i] === "<") {
this.rightType = "value";
return;
} else if (this.rightOfCursor[i] === '"') {
this.rightType = "attribute";
return;
} else {
this.rightType = "";
return;
}
}
};
/**
* Returns the tag name to be sent to autocompleter service.
* #returns {_L1.XHtmlTagInterpreter.prototype#pro;leftOfCursor#call;trim#call;replace|String}
*/
XHtmlTagInterpreter.prototype.getCompleteInfo = function() {
"use strict";
this.setLeftType();
this.setRightType();
if (this.leftType !== this.rightType) {
return "";
}
if (this.leftType === "value") {
var tagName = this.leftOfCursor.trim()
.replace(new RegExp("^.*<([a-z:]+).*?>$"), "$1");
return {completeType: "value", tagName: tagName};
} else if (this.leftType === "attribute") {
var tagName = this.leftOfCursor.trim()
.replace(new RegExp("^.*<([a-z:]+).*?([a-z:]+)\s*=\s*\"$"), "$1");
var attributeName = this.leftOfCursor.trim()
.replace(new RegExp("^.*<([a-z:]+).*?([a-z:]+)\s*=\s*\"$"), "$2");
return {completeType: "attribute", tagName: tagName,
attributeName: attributeName};
} else {
return null;
}
};
var loadEditor = function(editor) {
var chileCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {
var line = session.getLine(pos.row);
if (undefined !== line) {
var interpreter = new XHtmlTagInterpreter(pos.row,
pos.column, session);
var completeInfo = interpreter.getCompleteInfo();
if (undefined === completeInfo || completeInfo === null
|| undefined === completeInfo.completeType
|| completeInfo.completeType === null
|| completeInfo.completeType.length === 0
|| undefined === completeInfo.tagName
|| completeInfo.tagName === null
|| completeInfo.tagName.length === 0) {
callback(null, []);
return;
}
$.getJSON(chileContextPath
+ "services/mock/autocompleter/"
+ encodeURIComponent(completeInfo.completeType)
+ ".json?tagName="
+ encodeURIComponent(completeInfo.tagName)
+ "&attributeName="
+ encodeURIComponent(completeInfo.attributeName),
function(json) {
callback(null, json.content.map(function(c) {
return {value: c.value, caption: c.caption,
meta: c.meta, score:c.score};
}));
})
}
} else {
callback(null, []);
return;
}
}
};
editor = ace.edit("chile-editor");
editor.setOptions({
enableBasicAutocompletion: [chileCompleter],
enableLiveAutocompletion: true,
enableSnippets: true,
});
editor.setTheme("ace/theme/clouds");
editor.getSession().setMode("ace/mode/xml");
editor.getSession().setUseWrapMode(true);
editor = loadXKbml(editor);
return editor;
};

ng-grid export to CSV plugin -- how to download all data even if paged

Hi I am working with angular's ng-grid to display about 1000 rows of data. Users are allowed to view the data in the actual table 10, 20, or 100 rows at a time..but regardless of how much data they are viewing at a time, I want them to be able to download a CSV of all 1000 rows.
Is there a way to do this with the current plugin? I've been struggling for a while now since the plug in always goes to the actual ng-grid for the data to create a CSV from.
ng-grid plug in:
ngGridCsvExportPlugin = function(opts) {
var self = this;
self.grid = null;
self.scope = null;
self.init = function(scope, grid, services) {
self.grid = grid;
self.scope = scope;
function showDs() {
var keys = [];
for (var f in grid.config.columnDefs) { if (grid.config.columnDefs[f].field) { keys.push(grid.config.columnDefs[f].field); }}
var csvData = '';
function csvStringify(str) {
if (str == null) return ''; // we want to catch anything null-ish, hence just == not ===
if (typeof(str) === 'number') return '' + str;
if (typeof(str) === 'boolean') return (str ? 'TRUE' : 'FALSE') ;
if (typeof(str) === 'string') return str.replace(/"/g,'""');
return JSON.stringify(str).replace(/"/g,'""');
}
function swapLastCommaForNewline(str) {
var newStr = str.substr(0,str.length - 1);
return newStr + "\n";
}
for (var k in keys) {
csvData += '"' + csvStringify(keys[k]) + '",';
}
csvData = swapLastCommaForNewline(csvData);
var gridData = grid.data;
for (var gridRow in gridData) {
for ( k in keys) {
var curCellRaw;
if (opts != null && opts.columnOverrides != null && opts.columnOverrides[keys[k]] != null) {
curCellRaw = opts.columnOverrides[keys[k]](gridData[gridRow][keys[k]]);
} else {
curCellRaw = gridData[gridRow][keys[k]];
}
csvData += '"' + csvStringify(curCellRaw) + '",';
}
csvData = swapLastCommaForNewline(csvData);
}
var fp = grid.$root.find(".ngFooterPanel");
var csvDataLinkPrevious = grid.$root.find('.ngFooterPanel .csv-data-link-span');
if (csvDataLinkPrevious != null) {csvDataLinkPrevious.remove() ; }
var link = "data:text/csv;charset=UTF-8," + encodeURIComponent(csvData);
var csvDataLinkHtml = "<span class=\"csv-data-link-span\">";
csvDataLinkHtml += "<br><a class=\"btn hidden btn-primary exportTable2CSV\" href=" + link + " download=\"Export.csv\">CSV Export</a></br></span>" ;
fp.append(csvDataLinkHtml);
scope.$emit("exportTable2CSVLinkReady", link);
}
setTimeout(showDs, 0);
scope.catHashKeys = function() {
showDs();
hash = '';
for (idx in scope.renderedRows) { hash += scope.renderedRows[idx].$$hashKey; }
return hash;
};
scope.$watch('catHashKeys()', showDs);
};
};
You have all the data, maybe you can use ng-csv to export csv file.
Here is example. sfiddle
html:
<h2>Export {{sample}}</h2>
<div>
<button type="button" ng-csv="getArray" filename="test.csv">Export</button>
</div>
javascript :
angular.module('csv', ['ngCsv']);
function Main($scope) {
$scope.sample = "Sample";
$scope.getArray = [{a: 1, b:2}, {a:3, b:4}];
}
As per your explanation it is not clear what is undefined...
have you tried accessing data through scope not grid?
As you might have observed that there is no such hook/function which will export all data at once, so i suggest to make user change page selection to display all records only after that enable CSV export option?

Categories

Resources