Serializing to JSON in jQuery [duplicate] - javascript

This question already has answers here:
Serializing an object to JSON
(4 answers)
Closed 5 years ago.
I need to serialize an object to JSON. I'm using jQuery. Is there a "standard" way to do this?
My specific situation: I have an array defined as shown below:
var countries = new Array();
countries[0] = 'ga';
countries[1] = 'cd';
...
and I need to turn this into a string to pass to $.ajax() like this:
$.ajax({
type: "POST",
url: "Concessions.aspx/GetConcessions",
data: "{'countries':['ga','cd']}",
...

JSON-js - JSON in JavaScript.
To convert an object to a string, use JSON.stringify:
var json_text = JSON.stringify(your_object, null, 2);
To convert a JSON string to object, use JSON.parse:
var your_object = JSON.parse(json_text);
It was recently recommended by John Resig:
...PLEASE start migrating
your JSON-using applications over to
Crockford's json2.js. It is fully
compatible with the ECMAScript 5
specification and gracefully degrades
if a native (faster!) implementation
exists.
In fact, I just landed a change in jQuery yesterday that utilizes the
JSON.parse method if it exists, now
that it has been completely specified.
I tend to trust what he says on JavaScript matters :)
All modern browsers (and many older ones which aren't ancient) support the JSON object natively. The current version of Crockford's JSON library will only define JSON.stringify and JSON.parse if they're not already defined, leaving any browser native implementation intact.

I've been using jquery-json for 6 months and it works great. It's very simple to use:
var myObj = {foo: "bar", "baz": "wockaflockafliz"};
$.toJSON(myObj);
// Result: {"foo":"bar","baz":"wockaflockafliz"}

Works on IE8+
No need for jQuery, use:
JSON.stringify(countries);

I haven't used it but you might want to try the jQuery plugin written by Mark Gibson
It adds the two functions: $.toJSON(value), $.parseJSON(json_str, [safe]).

No, the standard way to serialize to JSON is to use an existing JSON serialization library. If you don't wish to do this, then you're going to have to write your own serialization methods.
If you want guidance on how to do this, I'd suggest examining the source of some of the available libraries.
EDIT: I'm not going to come out and say that writing your own serliazation methods is bad, but you must consider that if it's important to your application to use well-formed JSON, then you have to weigh the overhead of "one more dependency" against the possibility that your custom methods may one day encounter a failure case that you hadn't anticipated. Whether that risk is acceptable is your call.

I did find this somewhere. Can't remember where though... probably on StackOverflow :)
$.fn.serializeObject = function(){
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};

If you don't want to use external libraries there is .toSource() native JavaScript method, but it's not perfectly cross-browser.

Yes, you should JSON.stringify and JSON.parse your Json_PostData before calling $.ajax:
$.ajax({
url: post_http_site,
type: "POST",
data: JSON.parse(JSON.stringify(Json_PostData)),
cache: false,
error: function (xhr, ajaxOptions, thrownError) {
alert(" write json item, Ajax error! " + xhr.status + " error =" + thrownError + " xhr.responseText = " + xhr.responseText );
},
success: function (data) {
alert("write json item, Ajax OK");
}
});

The best way is to include the polyfill for JSON object.
But if you insist create a method for serializing an object to JSON notation (valid values for JSON) inside the jQuery namespace, you can do something like this:
Implementation
// This is a reference to JSON.stringify and provides a polyfill for old browsers.
// stringify serializes an object, array or primitive value and return it as JSON.
jQuery.stringify = (function ($) {
var _PRIMITIVE, _OPEN, _CLOSE;
if (window.JSON && typeof JSON.stringify === "function")
return JSON.stringify;
_PRIMITIVE = /string|number|boolean|null/;
_OPEN = {
object: "{",
array: "["
};
_CLOSE = {
object: "}",
array: "]"
};
//actions to execute in each iteration
function action(key, value) {
var type = $.type(value),
prop = "";
//key is not an array index
if (typeof key !== "number") {
prop = '"' + key + '":';
}
if (type === "string") {
prop += '"' + value + '"';
} else if (_PRIMITIVE.test(type)) {
prop += value;
} else if (type === "array" || type === "object") {
prop += toJson(value, type);
} else return;
this.push(prop);
}
//iterates over an object or array
function each(obj, callback, thisArg) {
for (var key in obj) {
if (obj instanceof Array) key = +key;
callback.call(thisArg, key, obj[key]);
}
}
//generates the json
function toJson(obj, type) {
var items = [];
each(obj, action, items);
return _OPEN[type] + items.join(",") + _CLOSE[type];
}
//exported function that generates the json
return function stringify(obj) {
if (!arguments.length) return "";
var type = $.type(obj);
if (_PRIMITIVE.test(type))
return (obj === null ? type : obj.toString());
//obj is array or object
return toJson(obj, type);
}
}(jQuery));
Usage
var myObject = {
"0": null,
"total-items": 10,
"undefined-prop": void(0),
sorted: true,
images: ["bg-menu.png", "bg-body.jpg", [1, 2]],
position: { //nested object literal
"x": 40,
"y": 300,
offset: [{ top: 23 }]
},
onChange: function() { return !0 },
pattern: /^bg-.+\.(?:png|jpe?g)$/i
};
var json = jQuery.stringify(myObject);
console.log(json);

It's basically 2 step process:
First, you need to stringify like this:
var JSON_VAR = JSON.stringify(OBJECT_NAME, null, 2);
After that, you need to convert the string to Object:
var obj = JSON.parse(JSON_VAR);

One thing that the above solutions don't take into account is if you have an array of inputs but only one value was supplied.
For instance, if the back end expects an array of People, but in this particular case, you are just dealing with a single person. Then doing:
<input type="hidden" name="People" value="Joe" />
Then with the previous solutions, it would just map to something like:
{
"People" : "Joe"
}
But it should really map to
{
"People" : [ "Joe" ]
}
To fix that, the input should look like:
<input type="hidden" name="People[]" value="Joe" />
And you would use the following function (based off of other solutions, but extended a bit)
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (this.name.substr(-2) == "[]"){
this.name = this.name.substr(0, this.name.length - 2);
o[this.name] = [];
}
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};

Related

Convert javascript object or array to json for ajax data

So I'm creating an array with element information. I loop through all elements and save the index. For some reason I cannot convert this array to a json object!
This is my array loop:
var display = Array();
$('.thread_child').each(function(index, value){
display[index]="none";
if($(this).is(":visible")){
display[index]="block";
}
});
I try to turn it into a JSON object by:
data = JSON.stringify(display);
It doesn't seem to send the proper JSON format!
If I hand code it like this, it works and sends information:
data = {"0":"none","1":"block","2":"none","3":"block","4":"block","5":"block","6":"block","7":"block","8":"block","9":"block","10":"block","11":"block","12":"block","13":"block","14":"block","15":"block","16":"block","17":"block","18":"block","19":"block"};
When I do an alert on the JSON.stringify object it looks the same as the hand coded one. But it doesn't work.
I'm going crazy trying to solve this! What am I missing here? What's the best way to send this information to get the hand coded format?
I am using this ajax method to send data:
$.ajax({
dataType: "json",
data:data,
url: "myfile.php",
cache: false,
method: 'GET',
success: function(rsp) {
alert(JSON.stringify(rsp));
var Content = rsp;
var Template = render('tsk_lst');
var HTML = Template({ Content : Content });
$( "#task_lists" ).html( HTML );
}
});
Using GET method because I'm displaying information (not updating or inserting). Only sending display info to my php file.
END SOLUTION
var display = {};
$('.thread_child').each(function(index, value){
display[index]="none";
if($(this).is(":visible")){
display[index]="block";
}
});
$.ajax({
dataType: "json",
data: display,
url: "myfile.php",
cache: false,
method: 'GET',
success: function(rsp) {
alert(JSON.stringify(rsp));
var Content = rsp;
var Template = render('tsk_lst');
var HTML = Template({ Content : Content });
$( "#task_lists" ).html( HTML );
}
});
I'm not entirely sure but I think you are probably surprised at how arrays are serialized in JSON. Let's isolate the problem. Consider following code:
var display = Array();
display[0] = "none";
display[1] = "block";
display[2] = "none";
console.log( JSON.stringify(display) );
This will print:
["none","block","none"]
This is how JSON actually serializes array. However what you want to see is something like:
{"0":"none","1":"block","2":"none"}
To get this format you want to serialize object, not array. So let's rewrite above code like this:
var display2 = {};
display2["0"] = "none";
display2["1"] = "block";
display2["2"] = "none";
console.log( JSON.stringify(display2) );
This will print in the format you want.
You can play around with this here: http://jsbin.com/oDuhINAG/1/edit?js,console
You can use JSON.stringify(object) with an object and I just wrote a function that'll recursively convert an array to an object, like this JSON.stringify(convArrToObj(array)), which is the following code (more detail can be found on this answer):
// Convert array to object
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
}
To make it more generic, you can override the JSON.stringify function and you won't have to worry about it again, to do this, just paste this at the top of your page:
// Modify JSON.stringify to allow recursive and single-level arrays
(function(){
// Convert array to object
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
};
var oldJSONStringify = JSON.stringify;
JSON.stringify = function(input){
return oldJSONStringify(convArrToObj(input));
};
})();
And now JSON.stringify will accept arrays or objects! (link to jsFiddle with example)
Edit:
Here's another version that's a tad bit more efficient, although it may or may not be less reliable (not sure -- it depends on if JSON.stringify(array) always returns [], which I don't see much reason why it wouldn't, so this function should be better as it does a little less work when you use JSON.stringify with an object):
(function(){
// Convert array to object
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
};
var oldJSONStringify = JSON.stringify;
JSON.stringify = function(input){
if(oldJSONStringify(input) == '[]')
return oldJSONStringify(convArrToObj(input));
else
return oldJSONStringify(input);
};
})();
jsFiddle with example here
js Performance test here, via jsPerf

How to use a different json parser for jQuery.ajax?

I have json data with "tagged" values (from a jsonp source):
{"foo": "#duration:8542"}
which I can parse on-the-fly by passing a function as the second argument to JSON.parse:
dk.json = {
parse: function (s) {
return JSON.parse(s, function (key, val) {
if (typeof val === 'string' && val[0] === '#') {
var colonpos = val.indexOf(':');
if (colonpos > 1) {
var tag = val.slice(0, colonpos + 1);
switch (tag) {
case dk.Date.tag: return dk.Date.create(val);
case dk.Duration.tag: return dk.Duration.create(val);
}
}
}
return val;
});
},
//...
};
but how can I plug this parsing function into jQuery.ajax()? Something more sensible than:
success: function (data) {
data = dk.json.parse(JSON.stringify(data));
...
dataFilter, and especially converters looked promising:
$.ajax({
dataType: 'jsonp',
converters: {
'text json': dk.json.parse
},
// ...
});
but that doesn't get called at all (dataFilter gets called, but with the data parameter set to undefined).
Where am I going wrong?
[Edit:]
I know I can write a traversal function that walks the JSON object returned by jQuery, eg:
function untag(val) {
if (typeof val === 'string' && val[0] === '#') {
var colonpos = val.indexOf(':');
if (colonpos > 1) {
var tag = val.slice(0, colonpos + 1);
switch (tag) {
case dk.Date.tag: return dk.Date.create(val);
case dk.Duration.tag: return dk.Duration.create(val);
}
}
}
return val;
}
var untag_json = function (jsonobj) {
var _traverse = function _traverse(obj, result) {
var value;
for (var attr in obj) {
value = obj[attr];
if (value && typeof value === 'object') {
result[attr] = _traverse(value, {});
} else {
result[attr] = untag(value);
}
}
return result;
};
return _traverse(jsonobj, {});
};
and then call it in the success handler:
success: function (data) {
data = untag_json(data);
...
but that seems like a lot of unnecessary work.. Is there no way to use the converters parameter to $.ajax to get access to the unparsed (i.e. text) json source?
There actually isn't any JSON parsing in a JSONP request (src), which can seem counter intuitive. What is happening is the string that is returning from the JSONP endpoint is evaluated as JavaScript (with a reference to a function that is defined (or added in dynamically) in the DOM making the JSONP request like this:
_callback({'foo':'#duration:8524'});
If you wanted to use your function you would need to make the endpoint return a String like this:
_callback("{'foo':'#duration:8524'}");
then in the JSONP callback you could call JSON.parse(). JSON parse is a rather safe way to process JSON so if this was easier to reason about then it would be a fine approach.
Hi you need to set this header application/json in the response from server side then you can simply set dataType:json or dataType:jsonp then you will not need to stringify or parse the json. You then just get objects, properties or arrays from json.
For example : in php we use
$json_string = "{"foo": "#duration:8542"}";
$json = json_decode($json_string);
$foo = $json->foo;
echo $foo;//prints #duration:8542
In jquery you can do this:
sucess:function(response) {
var foo = response.foo;
console.log(foo);
}
Hope this helps

Getting property key from json object

Preamble: I'm Italian, sorry for my bad English.
I need to retrieve the name of the property from a json object using javascript/jquery.
for example, starting from this object:
{
"Table": {
"Name": "Chris",
"Surname": "McDonald"
}
}
is there a way to get the strings "Name" and "Surname"?
something like:
//not working code, just for example
var jsonobj = eval('(' + previouscode + ')');
var prop = jsonobj.Table[0].getPropertyName();
var prop2 = jsonobj.Table[1].getPropertyName();
return prop + '-' + prop2; // this will return 'Name-Surname'
var names = [];
for ( var o in jsonobj.Table ) {
names.push( o ); // the property name
}
In modern browsers:
var names = Object.keys( jsonobj.Table );
You can browse the properties of the object:
var table = jsonobj.Table;
for (var prop in table) {
if (table.hasOwnProperty(prop)) {
alert(prop);
}
}
The hasOwnProperty test is necessary to avoid including properties inherited from the prototype chain.
In jquery you can fetch it like this:
$.ajax({
url:'path to your json',
type:'post',
dataType:'json',
success:function(data){
$.each(data.Table, function(i, data){
console.log(data.name);
});
}
});

Is there a Jquery function that can take a #ref id value from a parsed JSON string and point me to the referenced object?

I have been looking for an answer to this all afternoon and i cant seem to find the best way to accomplish what i need to.
My JSON string (returned from a web service) has circular references in it (#ref) which point to $id in the string. Now i know that if use jquery parseJSON it creates the javascript object and i can access properties a la myObject.MyPropertyName. However, when i get to a #ref, i am unsure how to get the object that ID points to (which i assume is already created as a result of the de-serialization...
Should i be iterating though the object and all its child objects until i find it, or is there an easier way?
$.ajax({
type: "POST",
url: "/Task.asmx/GetTask",
data: "{'id':'" + '27' + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
_Data = $.parseJSON(msg.d ? msg.d : msg);
_this.Company = _Data[0].t_Program.t_Company;
_this.Program = _Data[0].t_Program;
_this.Task = _Data[0];
},
complete: function () {
}
});
The area in question is _Data[0].t_Program because it does not return an object but rather returns
_Data[0].t_Program
{...}
$ref: "12"
I dont exactly know the best way to get the object with $id "12". Based on the posts below it seems i should loop through the existing object, but i was hoping there was a jquery function that did that...
Many Thanks!
No, jQuery is not natively capable of resolving circular references in objects converted from JSON.
The only library for that which I know is Dojo's dojox.json.ref module.
But, your server application serializes that JSON somehow. Don't tell me that the solution it uses does not offer a deserialisation algorithm!
As my friend Alan, the author of the Xerox Courier (RPC over the net) library, used to say to me, "there are no pointers on the wire."
In other words, it is impossible for a JSON representation of a data structure to be circular. (But a circular structure can be flattened into a non-circular JSON structure.) As the JSON site says:
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
No pointers!
So the entire JSON will have been turned into Javascript Objects and/or Arrays after the jQuery parseJSON operation completes.
If the original stucture's ref_id values were used as the property names in the JSON / Javascript object, then they'll all be there.
The real issue is that you need to understand how your server serialized its data structure into the JSON data structure. Look in your server-side code to determine that.
Then use Javascript to de-serialize the JSON structure back into the best Javascript structure to fit your needs.
Re: Should i be iterating though the object and all its child objects until i find it, or is there an easier way?
The easier way would be to go through the Javascript structure once, and build up an additional "indexing" object whose properties are the #ref_id and the values are the original structure/value.
Sample:
var jsonCyclicReferenceFixed = JsonRecursive.parse(jsonWithRefAndId);
(function(){
function type(value){
var t = typeof(value);
if( t == "object" && value instanceof Array) {
return "array";
}
if( t == "object" && value && "$id" in value && "$values" in value) {
return "array";
}
return t;
}
function TypeConverterFactory(){
var converters = {};
var defaultConverter = {
fromJson: function(value){ return value; },
toJson: function(value){ return value; },
};
this.create = function(type){
var converter = converters[type];
if(!converter) return defaultConverter;
return converter;
};
this.register = function(type, converter){
converters[type] = converter;
converter.valueConverter = this.valueConverter;
};
}
function ObjectConverter(){
this.fromJson = function(obj){
if( obj == null ) return null;
if( "$ref" in obj ){
var reference = this.dictionary[obj.$ref];
return reference;
}
if("$id" in obj){
this.dictionary[obj.$id] = obj;
delete obj.$id;
}
for(var prop in obj){
obj[prop] = this.valueConverter.convertFromJson(obj[prop]);
}
return obj;
}
this.toJson = function(obj){
var id = 0;
if(~(id = this.dictionary.indexOf(obj))){
return { "$ref" : (id + 1).toString() };
}
var convertedObj = { "$id" : this.dictionary.push(obj).toString() };
for(var prop in obj){
convertedObj[prop] = this.valueConverter.convertToJson(obj[prop]);
}
return convertedObj;
}
}
function ArrayConverter(){
var self = this;
this.fromJson = function(arr){
if( arr == null ) return null;
if("$id" in arr){
var values = arr.$values.map(function(item){
return self.valueConverter.convertFromJson(item);
});
this.dictionary[arr.$id] = values;
delete arr.$id;
return values;
}
return arr;
}
this.toJson = function(arr){
var id = 0;
if(~(id = this.dictionary.indexOf(arr))){
return { "$ref" : (id + 1).toString() };
}
var convertedObj = { "$id" : this.dictionary.push(arr).toString() };
convertedObj.$values = arr.map(function(arrItem){
return self.valueConverter.convertToJson(arrItem);
});
return convertedObj;
}
}
function ValueConverter(){
this.typeConverterFactory = new TypeConverterFactory();
this.typeConverterFactory.valueConverter = this;
this.typeConverterFactory.register("array", new ArrayConverter);
this.typeConverterFactory.register("object", new ObjectConverter);
this.dictionary = {};
this.convertToJson = function(valor){
var converter = this.typeConverterFactory.create(type(valor));
converter.dictionary = this.dictionary;
return converter.toJson(valor);
}
this.convertFromJson = function(valor){
var converter = this.typeConverterFactory.create(type(valor));
converter.dictionary = this.dictionary;
return converter.fromJson(valor);
}
}
function JsonRecursive(){
this.valueConverter = new ValueConverter();
}
JsonRecursive.prototype.convert = function(obj){
this.valueConverter.dictionary = [];
var converted = this.valueConverter.convertToJson(obj);
return converted;
}
JsonRecursive.prototype.parse = function(string){
this.valueConverter.dictionary = {};
var referenced = JSON.parse(string);
return this.valueConverter.convertFromJson(referenced);
}
JsonRecursive.prototype.stringify = function(obj){
var converted = this.convert(obj);
var params = [].slice.call(arguments, 1);
return JSON.stringify.apply(JSON, [converted].concat(params));
}
if(window){
if( window.define ){
//to AMD (require.js)
window.define(function(){
return new JsonRecursive();
});
}else{
//basic exposition
window.jsonRecursive = new JsonRecursive();
}
return;
}
if(global){
// export to node.js
module.exports = new JsonRecursive();
}
}());
Sample:
// a object recursive
// var parent = {};
// var child = {};
// parent.child = child;
// child.parent = parent;
//
//results in this recursive json
var json = '{"$id":"0","name":"Parent","child":{"$id":"1","name":"Child","parent":{"$ref":"0"}}}'
//Parsing a Recursive Json to Object with references
var obj = jsonRecursive.parse(json);
// to see results try console.log( obj );
alert(obj.name);
alert(obj.child.name);

Support for encoding query string or POST data in YUI?

How do you encode a javascript object/hash (pairs of properties and values) into a URL-encoded query string with YUI (2.7.0 or 3.0.0 Beta) ?
I want to do the equivalent of Object.toQueryString() from Prototype:
I need this to encode parameters for GET and POST requests with YAHOO.util.Connect.
It turns out YAHOO.util.Connect has a setForm() method to serialize a form but that still leaves me out cold to encode parameters for GET requests, or the 4th parameter of YAHOO.util.Connect.asyncRequest() to pass post data.
I've made this little helper for my own project.
var toQueryString = function(o) {
if(typeof o !== 'object') {
return false;
}
var _p, _qs = [];
for(_p in o) {
_qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
}
return _qs.join('&');
};
// And to use it
var qs = toQueryString({'foo' : 'bar'});
YUI3 has the io-form module, which you can instantiate in your call the use. It allows you to write code like this:
YUI().use('node', 'io-form', function(Y) {
Y.get('#formId').on('sumbit', function(e) {
e.preventDefault();
Y.io(postURL,
{
method: "POST",
on: {
complete: on_complete_handler
},
form: {
id: "formId"
}
});
}
});
This code will make a POST request to postURL, with all the input values from the form with id "formId" is submitted. This module also works for GET requests.
I ended up using something like this based on some code found on github. The function must handle posting arrays..
"Y" is a reference to "YAHOO"
/**
* Turns an object into its URL-encoded query string representation.
*
* #param {Object} obj Parameters as properties and values
*/
toQueryString: function(obj, name) {
var i, l, s = [];
if (Y.lang.isNull(obj) || Y.lang.isUndefined(obj)) {
return name ? encodeURIComponent(name) + '=' : '';
}
if (Y.lang.isBoolean(obj)) {
obj = obj ? 1 : 0;
}
if (Y.lang.isNumber(obj) || Y.lang.isString(obj)) {
return encodeURIComponent(name) + '=' + encodeURIComponent(obj);
}
if (Y.lang.isArray(obj)) {
name = name; // + '[]'; don't do this for Java (php thing)
for (i = 0, l = obj.length; i < l; i ++) {
s.push(arguments.callee(obj[i], name));
}
return s.join('&');
}
// now we know it's an object.
var begin = name ? name + '[' : '',
end = name ? ']' : '';
for (i in obj) {
if (obj.hasOwnProperty(i)) {
s.push(arguments.callee(obj[i], begin + i + end));
}
}
return s.join("&");
}
I see YUILibrary Ticket 2528174 refers to an accepted contribution on for this.
The Querystring Utility
Provides static methods to serialize objects to querystrings and deserialize objects from querystrings.
Three modules are available:
querystring - Both parse and stringify functionality
querystring-parse - Parse valid querystring into JavaScript objects
querystring-stringify - Serialize JavaScript objects into valid query strings

Categories

Resources