Related
I want to print a string in following manner 'abc',21,'email' in javascript how can I do. below is my code.
var data = [];
data.push('abc');
data.push(21);
data.push('email');
Write a function to quote a string:
function quote(s) {
return typeof s === 'string' ? "'"+s+"'" : s;
}
Now map your array and paste the elements together with a comma:
data . map(quote) . join(',')
Since joining with a comma is the default way to convert an array into a string, you might be able to get away without the join in some situations:
alert (data . map(quote));
since alert converts its parameter into a string. Same with
element.textContent = data . map(quote);
if data is an array defined as
var data = [];
data.push('abc');
data.push(21);
data.push('email');
the use join() method of array to join (concatenate) the values by specifying the separator
try
alert( "'" + data.join("','") + "'" );
or
console.log( "'" + data.join("','") + "'" );
or simply
var value = "'" + data.join("','") + "'" ;
document.body.innerHTML += value;
Now data = ['abc', 21, 'email'];
So we can use forEach function
var myString = '';
data.forEach(function(value, index){
myString += typeof value === 'string' ? "'" + value + "'" : value;
if(index < data.length - 1) myString += ', ';
});
console.log(myString)
Shorter version:
myString = data.map(function(value){
return typeof value === 'string' ? "'" + value + "'" : value;
}).join(', ');
console.log(myString);
JSFiddle: https://jsfiddle.net/LeoAref/ea5fa3de/
I have a JSON string of the form:
[
{"ID":153,"CircuitID":53,"StartTime":"2014-11-12 12:45:00","EventFormatID":224,"TotalPlaces":8,"BookedPlaces":0,"ProvisionalPlaces":0},
{"ID":161,"CircuitID":53,"StartTime":"2014-11-12 17:15:00","EventFormatID":224,"TotalPlaces":0,"BookedPlaces":0,"ProvisionalPlaces":0},
{"ID":734,"CircuitID":53,"StartTime":"2014-11-12 18:30:00","EventFormatID":231,"TotalPlaces":14,"BookedPlaces":0,"ProvisionalPlaces":0}
]
In place of Event Format ID and Circuit ID I will be returning the names
What I need to do is group the results by Event Format ID and return the results in the following format:
Event 224 : 12:45 (8 places available), 17:15 (0 places available)
Event 231 : 18:30 (14 places available)
I can't seem to figure out how to loop through the data, group it by Event Format ID to present it in the required format!
Thanks
Can you use any additional libraries? I'd use lo-dash which would make this relatively simple:
var grouped = _.groupBy(data, "EventFormatID");
_(grouped).forEach(function (group, key) {
console.log("Event:" + key);
_(group).forEach(function (course) {
console.log(course.StartTime + " (" + course.TotalPlaces + " places available)");
});
});
Obviously the example above logs to the console but it'd be fairly simple to change to build up whatever string or object you need.
This is easier with lodash/underscore, or even with ES5 array and object methods, but since you asked about pure JS:
var data = {}, results = [], i, j, id, time, obj, evts; // obj is your object above
for (i=0; i<obj.length; i++) {
id = obj[i].EventFormatID;
time = obj[i].StartTime; // you can simplify to get just the time, not the datetime, if you prefer
data[id] = data[id] || [];
data[id].push({"time":time,"places":obj[i].TotalPlaces});
}
// now you have a proper data structure, just print it out
for (i in data) {
if (data.hasOwnProperty(i)) {
// just show the output properly formatted
evts = [];
for (j=0;i<data[i].length;j++) {
evts.push(data[i][j].time+" ("+data[i][j].places+" places available)");
}
results.push("Event "+i+" : "+evts.join(","));
}
}
ES5 makes this so much easier
var data = {}, results = [], obj; // obj is your object above
obj.forEach(function(val,i) {
data[val.EventFormatID] = data[val.EventFormatID] || [];
data[val.EventFormatID].push({"time":val.StartTime,"places":val.TotalPlaces});
});
// now you have a proper data structure, just print it out
Object.keys(data).forEach(function(key) {
var value = data[key], evts = [];
value.forEach(function(elm) {
evts.push(elm.time+" ("+elm.places+" places available)");
});
results.push("Event "+key+" : "+evts.join(","));
});
And lodash is even easier.
Please take a look that:
http://jsfiddle.net/m260n5ud/
html
<div id="contentDiv"></div>
js
function tidyUp(jsonArray) {
var myObject = {};
for (i = 0; i < jsonArray.length; i++) {
var key = jsonArray[i]['EventFormatID'];
var time = jsonArray[i]['StartTime'].replace(' ', ':').split(/[- :]/);
time = time[3] + ":" + time[4];
var totalPlace = jsonArray[i]['TotalPlaces'];
if (myObject[key] == null) {
myObject[key] = "Event : " + key + " : " + time + " ( " + totalPlace + " places available)";
} else {
myObject[key] += ", " + time + " ( " + totalPlace + " places available)";
}
}
console.log(myObject);
for (var k in myObject) {
document.getElementById('contentDiv').innerHTML += myObject[k] + "<br/>";
}
}
I'm trying to find a way to "pretty print" a JavaScript data structure in a human-readable form for debugging.
I have a rather big and complicated data structure being stored in JS and I need to write some code to manipulate it. In order to work out what I'm doing and where I'm going wrong, what I really need is to be able to see the data structure in its entirety, and update it whenever I make changes through the UI.
All of this stuff I can handle myself, apart from finding a nice way to dump a JavaScript data structure to a human-readable string. JSON would do, but it really needs to be nicely formatted and indented. I'd usually use Firebug's excellent DOM dumping stuff for this, but I really need to be able to see the entire structure at once, which doesn't seem to be possible in Firebug.
Use Crockford's JSON.stringify like this:
var myArray = ['e', {pluribus: 'unum'}];
var text = JSON.stringify(myArray, null, '\t'); //you can specify a number instead of '\t' and that many spaces will be used for indentation...
Variable text would look like this:
[
"e",
{
"pluribus": "unum"
}
]
By the way, this requires nothing more than that JS file - it will work with any library, etc.
I wrote a function to dump a JS object in a readable form, although the output isn't indented, but it shouldn't be too hard to add that: I made this function from one I made for Lua (which is much more complex) which handled this indentation issue.
Here is the "simple" version:
function DumpObject(obj)
{
var od = new Object;
var result = "";
var len = 0;
for (var property in obj)
{
var value = obj[property];
if (typeof value == 'string')
value = "'" + value + "'";
else if (typeof value == 'object')
{
if (value instanceof Array)
{
value = "[ " + value + " ]";
}
else
{
var ood = DumpObject(value);
value = "{ " + ood.dump + " }";
}
}
result += "'" + property + "' : " + value + ", ";
len++;
}
od.dump = result.replace(/, $/, "");
od.len = len;
return od;
}
I will look at improving it a bit.
Note 1: To use it, do od = DumpObject(something) and use od.dump. Convoluted because I wanted the len value too (number of items) for another purpose. It is trivial to make the function return only the string.
Note 2: it doesn't handle loops in references.
EDIT
I made the indented version.
function DumpObjectIndented(obj, indent)
{
var result = "";
if (indent == null) indent = "";
for (var property in obj)
{
var value = obj[property];
if (typeof value == 'string')
value = "'" + value + "'";
else if (typeof value == 'object')
{
if (value instanceof Array)
{
// Just let JS convert the Array to a string!
value = "[ " + value + " ]";
}
else
{
// Recursive dump
// (replace " " by "\t" or something else if you prefer)
var od = DumpObjectIndented(value, indent + " ");
// If you like { on the same line as the key
//value = "{\n" + od + "\n" + indent + "}";
// If you prefer { and } to be aligned
value = "\n" + indent + "{\n" + od + "\n" + indent + "}";
}
}
result += indent + "'" + property + "' : " + value + ",\n";
}
return result.replace(/,\n$/, "");
}
Choose your indentation on the line with the recursive call, and you brace style by switching the commented line after this one.
... I see you whipped up your own version, which is good. Visitors will have a choice.
You can use the following
<pre id="dump"></pre>
<script>
var dump = JSON.stringify(sampleJsonObject, null, 4);
$('#dump').html(dump)
</script>
In Firebug, if you just console.debug ("%o", my_object) you can click on it in the console and enter an interactive object explorer. It shows the entire object, and lets you expand nested objects.
For Node.js, use:
util.inspect(object, [options]);
API Documentation
For those looking for an awesome way to see your object, check prettyPrint.js
Creates a table with configurable view options to be printed somewhere on your doc. Better to look than in the console.
var tbl = prettyPrint( myObject, { /* options such as maxDepth, etc. */ });
document.body.appendChild(tbl);
I'm programming in Rhino and I wasn't satisfied with any of the answers that were posted here. So I've written my own pretty printer:
function pp(object, depth, embedded) {
typeof(depth) == "number" || (depth = 0)
typeof(embedded) == "boolean" || (embedded = false)
var newline = false
var spacer = function(depth) { var spaces = ""; for (var i=0;i<depth;i++) { spaces += " "}; return spaces }
var pretty = ""
if ( typeof(object) == "undefined" ) { pretty += "undefined" }
else if ( typeof(object) == "boolean" ||
typeof(object) == "number" ) { pretty += object.toString() }
else if ( typeof(object) == "string" ) { pretty += "\"" + object + "\"" }
else if ( object == null) { pretty += "null" }
else if ( object instanceof(Array) ) {
if ( object.length > 0 ) {
if (embedded) { newline = true }
var content = ""
for each (var item in object) { content += pp(item, depth+1) + ",\n" + spacer(depth+1) }
content = content.replace(/,\n\s*$/, "").replace(/^\s*/,"")
pretty += "[ " + content + "\n" + spacer(depth) + "]"
} else { pretty += "[]" }
}
else if (typeof(object) == "object") {
if ( Object.keys(object).length > 0 ){
if (embedded) { newline = true }
var content = ""
for (var key in object) {
content += spacer(depth + 1) + key.toString() + ": " + pp(object[key], depth+2, true) + ",\n"
}
content = content.replace(/,\n\s*$/, "").replace(/^\s*/,"")
pretty += "{ " + content + "\n" + spacer(depth) + "}"
} else { pretty += "{}"}
}
else { pretty += object.toString() }
return ((newline ? "\n" + spacer(depth) : "") + pretty)
}
The output looks like this:
js> pp({foo:"bar", baz: 1})
{ foo: "bar",
baz: 1
}
js> var taco
js> pp({foo:"bar", baz: [1,"taco",{"blarg": "moo", "mine": "craft"}, null, taco, {}], bleep: {a:null, b:taco, c: []}})
{ foo: "bar",
baz:
[ 1,
"taco",
{ blarg: "moo",
mine: "craft"
},
null,
undefined,
{}
],
bleep:
{ a: null,
b: undefined,
c: []
}
}
I've also posted it as a Gist here for whatever future changes may be required.
jsDump
jsDump.parse([
window,
document,
{ a : 5, '1' : 'foo' },
/^[ab]+$/g,
new RegExp('x(.*?)z','ig'),
alert,
function fn( x, y, z ){
return x + y;
},
true,
undefined,
null,
new Date(),
document.body,
document.getElementById('links')
])
becomes
[
[Window],
[Document],
{
"1": "foo",
"a": 5
},
/^[ab]+$/g,
/x(.*?)z/gi,
function alert( a ){
[code]
},
function fn( a, b, c ){
[code]
},
true,
undefined,
null,
"Fri Feb 19 2010 00:49:45 GMT+0300 (MSK)",
<body id="body" class="node"></body>,
<div id="links">
]
QUnit (Unit-testing framework used by jQuery) using slightly patched version of jsDump.
JSON.stringify() is not best choice on some cases.
JSON.stringify({f:function(){}}) // "{}"
JSON.stringify(document.body) // TypeError: Converting circular structure to JSON
Taking PhiLho's lead (thanks very much :)), I ended up writing my own as I couldn't quite get his to do what I wanted. It's pretty rough and ready, but it does the job I need. Thank you all for the excellent suggestions.
It's not brilliant code, I know, but for what it's worth, here it is. Someone might find it useful:
// Usage: dump(object)
function dump(object, pad){
var indent = '\t'
if (!pad) pad = ''
var out = ''
if (object.constructor == Array){
out += '[\n'
for (var i=0; i<object.length; i++){
out += pad + indent + dump(object[i], pad + indent) + '\n'
}
out += pad + ']'
}else if (object.constructor == Object){
out += '{\n'
for (var i in object){
out += pad + indent + i + ': ' + dump(object[i], pad + indent) + '\n'
}
out += pad + '}'
}else{
out += object
}
return out
}
For anyone checking this question out in 2021 or post-2021
Check out this Other StackOverflow Answer by hassan
TLDR:
JSON.stringify(data,null,2)
here the third parameter is the tab/spaces
This is really just a comment on Jason Bunting's "Use Crockford's JSON.stringify", but I wasn't able to add a comment to that answer.
As noted in the comments, JSON.stringify doesn't play well with the Prototype (www.prototypejs.org) library. However, it is fairly easy to make them play well together by temporarily removing the Array.prototype.toJSON method that prototype adds, run Crockford's stringify(), then put it back like this:
var temp = Array.prototype.toJSON;
delete Array.prototype.toJSON;
$('result').value += JSON.stringify(profile_base, null, 2);
Array.prototype.toJSON = temp;
I thought J. Buntings response on using JSON.stringify was good as well. A an aside, you can use JSON.stringify via YUIs JSON object if you happen to be using YUI. In my case I needed to dump to HTML so it was easier to just tweak/cut/paste PhiLho response.
function dumpObject(obj, indent)
{
var CR = "<br />", SPC = " ", result = "";
if (indent == null) indent = "";
for (var property in obj)
{
var value = obj[property];
if (typeof value == 'string')
{
value = "'" + value + "'";
}
else if (typeof value == 'object')
{
if (value instanceof Array)
{
// Just let JS convert the Array to a string!
value = "[ " + value + " ]";
}
else
{
var od = dumpObject(value, indent + SPC);
value = CR + indent + "{" + CR + od + CR + indent + "}";
}
}
result += indent + "'" + property + "' : " + value + "," + CR;
}
return result;
}
Lots of people writing code in this thread, with many comments about various gotchas. I liked this solution because it seemed complete and was a single file with no dependencies.
browser
nodejs
It worked "out of the box" and has both node and browser versions (presumably just different wrappers but I didn't dig to confirm).
The library also supports pretty printing XML, SQL and CSS, but I haven't tried those features.
A simple one for printing the elements as strings:
var s = "";
var len = array.length;
var lenMinus1 = len - 1
for (var i = 0; i < len; i++) {
s += array[i];
if(i < lenMinus1) {
s += ", ";
}
}
alert(s);
My NeatJSON library has both Ruby and JavaScript versions. It is freely available under a (permissive) MIT License. You can view an online demo/converter at:
http://phrogz.net/JS/neatjson/neatjson.html
Some features (all optional):
Wrap to a specific width; if an object or array can fit on the line, it is kept on one line.
Align the colons for all keys in an object.
Sort the keys to an object alphabetically.
Format floating point numbers to a specific number of decimals.
When wrapping, use a 'short' version that puts the open/close brackets for arrays and objects on the same line as the first/last value.
Control the whitespace for arrays and objects in a granular manner (inside brackets, before/after colons and commas).
Works in the web browser and as a Node.js module.
flexjson includes a prettyPrint() function that might give you what you want.
I have a little function that makes URL arguments out of an object:
function MkArgs(o) {
var ret = '?';
for (var i in o) {
ret += i + '=' + escape(o[i]) + '&';
}
return ret.substr(0, ret.length - 1);
}
which I then can call like this:
MkArgs({
protocol: 'wsfederation',
realm: 'https://www.x.com/',
fedRes: 'Home/FederationResult',
context: '~/Home/FAQ',
version: '1.0',
callback: '?'
});
to produce the following:
?protocol=wsfederation&realm=https%3A//www.x.com/&fedRes=Home/FederationResult&context=%7E/Home/FAQ&version=1.0&callback=%3F
everything is fine except that I don't want the last argument escaped i.e. I want:
callback=?
instead of
callback=%3F
is there any way I can indicate that within the string? I tried '\?' but that doesn't do it and haven't found any references as to how to protect a piece of string from escaping...
e
The MkArgs function is your own; change it to include an escape mechanism. I would advise against using backslash, though. If this is just your own code, perhaps it would be enough to put in a hackish special case.
That's a pretty special case. Maybe you should change your function:
function MkArgs(o, isJSONP) {
var ret = '?';
for (var i in o) {
var val = o[i];
val = escape(val);
ret += i + '=' + val + '&';
}
return ret.substr(0, ret.length - 1) + isJSONP ? '&callback=?':'';
}
and call it:
MkArgs({
protocol: 'wsfederation',
realm: 'https://www.x.com/',
fedRes: 'Home/FederationResult',
context: '~/Home/FAQ',
version: '1.0'
}, true);
The escape or encodeURIComponent functions don't have any way of "skipping" certain characters. So, all you can do is to either avoid calling the encode function when you don't want to or replace the chars you don't want encoded, call encode and then put the original chars back again.
If you want to skip escaping the whole value for a particular key, you can just check for the particular keys that you don't want to escape and handle appropriately like this:
function MkArgs(o) {
var ret = '?';
for (var i in o) {
var val = o[i];
if (i != "callback") {
val = encodeURIComponent(val);
}
ret += i + '=' + val + '&';
}
return ret.substr(0, ret.length - 1);
}
If you want to skip just certain characters, then you can replace them with some unique sequence, escape and then put them back:
function MkArgs(o) {
var ret = '?';
for (var i in o) {
var val = o[i];
if (i == "callback") {
val = val.replace(/\?/, "--xx--"); // replace with unique sequence
val = encodeURIComponent(val);
val = val.replace(/--xx--/, "?"); // put orig characters back
} else {
val = encodeURIComponent(val);
}
ret += i + '=' + val + '&';
}
return ret.substr(0, ret.length - 1);
}
FYI, note I've switched to using encodeURIComponent() which is recommended over the deprecated escape() because escape() doesn't work for non-ascii characters.
thanks everyone for the replies. what I ended up doing was:
function MkArgs(o) {
var ret = '?';
for (var i in o) {
ret += i;
if (o[i]) ret += '=' + escape(o[i]);
ret += '&';
}
return ret.substr(0, ret.length - 1);
}
then calling it like:
MkArgs({
protocol: 'wsfederation',
realm: 'https://www.x.com/',
fedRes: 'Home/FederationResult',
context: '~/Home/FAQ',
version: '1.0',
'callback=?': null
});
that way I don't rely on the values but the keys to make the distinction. not really pretty but it's the best I could think of
function MkArgs(o) {
var ret = '?';
var lastEl = '';
for (var i in o) {
ret += i + '=' + escape(o[i]) + '&';
lastEl = o[i];
}
return ret.substr(0, ret.length - 1 - lastEl.length) + lastEl;
}
this works for the last element in the object.
EDIT: It seems that in a classic for in loop, javascript does not have a precise order in which it loops over the object props, so the above solution is not guaranteed to work.
In this case you have 2 solutions :
If you know which property you want to "protect" from escaping, you should check for that prop in the loop and specifically not escape it :
for (var i in o) {
if(i=="myProp")
// unescape
else
// escape
}
If you do not now the property, but you want only the last one added into the query, you can do something like this (after building the query) :
var q = MkArgs(o);
var parts = q.split('=');
var toUnescape = parts[parts.length-1];
q = q.substring(0,q.length - toUnescape.length) + unescape(toUnescape);
the list looks like:
3434,346,1,6,46
How can I append a number to it with javascript, but only if it doesn't already exist in it?
Assuming your initial value is a string (you didn't say).
var listOfNumbers = '3434,346,1,6,46', add = 34332;
var numbers = listOfNumbers.split(',');
if(numbers.indexOf(add)!=-1) {
numbers.push(add);
}
listOfNumbers = numbers.join(',');
Basically i convert the string into an array, check the existence of the value using indexOf(), adding only if it doesn't exist.
I then convert the value back to a string using join.
If that is a string, you can use the .split() and .join() functions, as well as .push():
var data = '3434,346,1,6,46';
var arr = data.split(',');
var add = newInt;
arr.push(newInt);
data = arr.join(',');
If that is already an array, you can just use .push():
var data = [3434,346,1,6,46];
var add = newInt;
data.push(add);
UPDATE: Didn't read the last line to check for duplicates, the best approach I can think of is a loop:
var data = [3434,346,1,6,46];
var add = newInt;
var exists = false;
for (var i = 0; i < input.length; i++) {
if (data[i] == add) {
exists = true;
break;
}
}
if (!exists) {
data.push(add);
// then you would join if you wanted a string
}
You can also use a regular expression:
function appendConditional(s, n) {
var re = new RegExp('(^|\\b)' + n + '(\\b|$)');
if (!re.test(s)) {
return s + (s.length? ',' : '') + n;
}
return s;
}
var nums = '3434,346,1,6,46'
alert( appendConditional(nums, '12') ); // '3434,346,1,6,46,12'
alert( appendConditional(nums, '6') ); // '3434,346,1,6,46'
Oh, since some really like ternary operators and obfustically short code:
function appendConditional(s, n) {
var re = new RegExp('(^|\\b)' + n + '(\\b|$)');
return s + (re.test(s)? '' : (''+s? ',':'') + n );
}
No jQuery, "shims" or cross-browser issues. :-)