I am trying to get rid of the jQuery dependency in a project. One thing that project does is posting data to a server like so:
var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
$.post( url, data);
Thanks to You might not need jQuery, I know how to rewrite $.post in pure Javascript using XMLHttpRequest:
var request = new XMLHttpRequest();
request.open( 'POST', url, true);
request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send( data);
Unfortunately, this description seems to assume that the data object is already a URL-encoded query string, which is clearly not the case in the above example. It turns out jQuery does more than that: With the given data object, the above $.post call would first convert it to a query string, which would look like so:
apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit
The code snippet using XMLHttpRequest does not do so, and, thus, the server will throw errors at me.
jQuery also has a wonderful method call $.param which does exactly this conversion. The above code snippet using XMLHttpRequest will work marvelously if in the last line I do
request.send( $.param(data));
But then, I did not get rid of the jQuery dependency. So I'm looking for a pure Javascript equivalent of $.param. Does anyone have something like that?
Note: The question Plain Javascript Equivalent of jQuery.param() asks a similar question, but the accepted answer only works in very simple cases. Applying the function given in that answer to my above data object yields:
apple=%5Bobject%20Object%5D%2C%5Bobject%20Object%5D&pear=passion%20fruit
...which is obviously different from the result of $.param(data) given above, and loses information since it doesn't work recursively.
I have made a quick function for you which should achieve this for you, it will create parameters from your key=>value pairs and stringify your non primitive values.
var objToParams = function(obj){
var paramString = '';
for (var key in data) {
var value = obj[key];
if(obj[key] instanceof Array || obj[key] instanceof Object){
value = encodeURIComponent(JSON.stringify(value));
}
if (paramString != "") paramString += "&";
paramString += key + "=" + encodeURIComponent(value);
}
return paramString;
}
var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
console.log(objToParams(data));
http://jsfiddle.net/7buy3rjy/
Edit, from your comment this should work and is now matching the output of $.param:
http://jsfiddle.net/mg511z7w/
var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
var stringifyParam = function(data, topLevel, keyProp) {
var string = '';
for (var key in data) {
if(keyProp && topLevel[keyProp] ) {
if ( (topLevel[keyProp] instanceof Array&&topLevel[keyProp].indexOf(data[key])!==0) ) {
string += keyProp;
} else if ( (topLevel[keyProp] instanceof Object&&topLevel[keyProp][key]) ) {
string += keyProp;
}
}
if (typeof(topLevel[key])=='undefined') {
string += '[' + key + ']';
}
if (data[key] instanceof Array) {
string += stringifyParam(data[key], topLevel, key);
} else if(data[key] instanceof Object){
string += stringifyParam(data[key], topLevel, key);
} else {
if (typeof(topLevel[key])!='undefined') {
string += key;
}
string += '=' + data[key];
string += '&';
}
}
return string;
},
toParam = function(data){
var string = stringifyParam(data,data);
return encodeURI(string.substring(0,string.length-1).split(' ').join('+'));
};
console.log(toParam(data)); //apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit
console.log($.param(data)); //apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit
You could go about doing recursive code but why not try the simple scheme JSON, which was why it was created - To exchange data between client and server in an easier manner.
Just do this
request.send(JSON.stringify(data));
JSON.stringify accepts an Object which will then be converted to a valid JSON, which can be parsed in the server-side.
To know more about the JSON, there can't be a better way than going through it's tag excerpt here
you could use encode and decode URIComponent functions to accomplish this.
edit
what about this:
var qs = Object.keys(obj).reduce(function(a,k){
a.push(k+'='+encodeURIComponent(JSON.stringify(obj[k])));
return a;
},[]).join('&');
// "apple=%5B%7B%22kiwi%22%3A%22orange%22%7D%2C%7B%22banana%22%3A%22lemon%22%7D%5D&pear=%22passion%20fruit%22"
instead of this:
var obj = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
var data = encodeURIComponent(JSON.stringify(obj));
// "%7B%22apple%22%3A%5B%7B%22kiwi%22%3A%22orange%22%7D%2C%7B%22banana%22%3A%22lemon%22%7D%5D%2C%22pear%22%3A%22passion%20fruit%22%7D"
var obj2 = JSON.parse(decodeURIComponent(data));
// {"apple":[{"kiwi":"orange"},{"banana":"lemon"}],"pear":"passion fruit"}
Related
I have a csv file which has the following data format:
2001:200::,2001:200:ffff:ffff:ffff:ffff:ffff:ffff,
42540528726795050063891204319802818560,42540528806023212578155541913346768895,JP,,,36.0000,138.0000,,0,0
2001:208::,2001:208:ffff:ffff:ffff:ffff:ffff:ffff,
42540529360620350178005905068154421248,42540529439848512692270242661698371583,SG,,,1.3667,103.8000,,0,0
I want to only parse the item after the 1st comma (IPv6 address), and the lat/long (36.0000,138.0000 in the first record) values for this record.
How can I use JavaScript/ jQuery to do this?
Use the split method to turn the string into an array and then iterate thru it as you wish.
var csv = "2001:200::,2001:200:ffff:ffff:ffff:ffff:ffff:ffff,4254052872679505006389120431980\n2818560,42540528806023212578155541913346768895,JP,,,36.0000,138.0000,,0,0";
var myArray = csv.split("\n");//You should know what kind of new line your csv is using
myArray.map(function (e) { //Applies this function over each element of myArray that is each line of your csv
var line = e.split(","); //Turn the comma separated string into an array
return "The second element is: " + line[1]; //Do what you need
});
Well the same way you would in any language. First you open the file. Read it line by line. Split each line on the comma. Use the index of the array to get the value you want.
jQuery.get('file.csv', function(data) {
alert(data); // this is a line
var tempArray = data.split(','); // array of data
for(var i = 0; i < tempArray.length; i++)
{
console.log(tempArray[i]); // probably index 1 is your IPv6 address.
}
});
Or just use CSV libraries, I'd suggest PapaParse(Browser) or BabyParse(NodeJS)
Here's what you do :
$.ajax({
type: "GET",
url: "data.csv",
success: function (data) {
var data = Papa.parse(data);
var output = {
"IPv6" : data.data[0][1],
"coordinates" : [data.data[1][5], data.data[1][6]]
} /* -> These are the values you're looking for! */
}
});
Because I can't demo the AJAX (due to cross-domain scripting issues), I'll demo just the success function below!
Demo
var data = '2001:200::,2001:200:ffff:ffff:ffff:ffff:ffff:ffff,'+ "\n" +
'42540528726795050063891204319802818560,42540528806023212578155541913346768895,JP,,,36.0000,138.0000,,0,0'+ "\n\n" +
'2001:208::,2001:208:ffff:ffff:ffff:ffff:ffff:ffff,'+ "\n" +
'42540529360620350178005905068154421248,42540529439848512692270242661698371583,SG,,,1.3667,103.8000,,0,0';
var success = function (data) {
var data = Papa.parse(data);
return output = {
"IPv6" : data.data[0][1],
"coordinates" : [data.data[1][5], data.data[1][6]]
}
}
document.body.innerHTML = '<pre>' + JSON.stringify(success(data), null, 2) + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.2/papaparse.js"></script>
Given (as a post response body):
RESULT: OK
RESULT_PS: FINISHED
RESULT_CODE: 000
I need to serialize it to json, I use node's request to get this from server.
Surely I can parse it string by string.
But isn't there an easier way?
Maybe ready serializer or something to serialize such data to JSON?
What format is this?
filter each line from following code
var jsonObject = {}
function parser(str){
var arr = str.split(":");
jsonObject[arr[0]] = arr[1];
}
your final jsonObject is json you needed.
Make sure that you need to pass RESULT: OK, RESULT_PS: FINISHED,RESULT_CODE: 000 as seperate strings from parser.
As far as I can tell, this is just a delimited plain text response. (Where are you getting it from? Transaction response?) However, since it's that simple it's easily parseable with a quick map-reduce operation.
function trim(str) {
return str.replace(/^\s+|\s+$/g, "");
}
function nonEmpty(str) {
return null != str && str.length > 0;
}
function splitKeyValue(row) {
var tokens = row.split(":").map(trim);
// My assumption that a row should only contain 2 colon separated tokens
if (tokens.length > 2) {
throw new Error("Malformed row: " + row);
}
return tokens;
}
function merge(acc, item) {
// Normalise key to lower case, to guarantee spelling
acc[item[0].toLowerCase()] = item[1];
return acc;
}
function parseResponse(payload) {
return payload.split("\n").
filter(nonEmpty).
map(splitKeyValue).
reduce(merge, {});
}
Using the snippet of code above, the result should be:
var payload =
"RESULT: OK\n" +
"RESULT_PS: FINISHED\n" +
"RESULT_CODE: 000\n";
var parsed = parseResponse(payload);
console.log(parsed);
// Output:
// {
// result: "OK",
// result_ps: "FINISHED",
// result_code: "000"
// }
// Each separate field is then accessible from it's name
console.log(parsed.result); // Output: "OK"
Ok, didn't find any ready solution.
So wrote this function:
parseResponse = function(response) {
var result = { };
response.replace(/([^\s:]+)\s*:\s*([^\n\s]+)/gi, function() {
var key = arguments[1], value = decodeURIComponent(arguments[2]);
result[key] = !isNaN(parseFloat(value)) && isFinite(value) ? parseFloat(value) : value;
});
return result;
}
If you use node.js there is handy module called querystring:
const querystring = require('querystring'),
payload =
"RESULT: OK\n\r" +
"RESULT_PS: FINISHED\n" +
"RESULT_CODE: 000\n";
let parsed = querystring.parse(payload, '\n', ':', {decodeURIComponent: s => s.trim()});
console.log(parsed);
For browsers there is a lot of good methods described in answers. Here is another one (vanilla JS):
var payload =
"RESULT: OK\n\r" +
"RESULT_PS: FINISHED\n" +
"RESULT_CODE: 000\n";
var browserParsed = payload.split("\n")
.map(function (s) {
return s.trim().split(":");
})
.filter(function (s) {
return s.length && s.length > 1;
})
.reduce(function (acc, c) {
acc[ c[ 0 ].trim() ] = c[ 1 ].trim();
return acc;
}, {});
console.log(browserParsed);
I am trying to traverse a JSON object with jQuery recursive.. normally it worked , but not on the following JSON.
I want to traverse this JSON, here I uploaded an image:
For my json objects, i had this jquery function:
var construct_id = "#ecommerce_form_";
// function to traverse json objects given back from Serializer class
function process(callback, id) {
var key;
for (key in callback) {
// Handle the arrays
if ('length' in callback[key]) {
// Handle the end - we found a string
if (typeof callback[key][0] == "string") {
var field_id = construct_id + id + key;
var err_msg = callback[key][0];
$(field_id).tooltip('destroy');
$(field_id).tooltip({'title': err_msg});
$(field_id).closest('div[class="form-group"]').addClass('has-error');
console.log(field_id, ":", err_msg);
}
// Else we found something else, so recurse.
else {
var i = 0;
while (i < callback[key].length) {
process(callback[key][i], key + "_" + i + "_");
i++;
}
}
}
// Handle the objects by recursing.
else {
process(callback[key], key + "_");
}
}
}
But that functions fails when trying to build the contact > addresses id with the error message:
"Uncaught TypeError: Cannot use 'in' operator to search for 'length'
in This value should not be blank."
Hope you guys can help me enhancing the jQuery function, it is not 100% successfull as you can see on this json example.
Regards
You are trying to search for the property "length" in a string, which can't be done. In the erroneous iteration: callback = obj.contacts.addresses, key = cities and then callback[key][0] = "This value should not be blank".
What you should do is check if you have reached a string before looking for the "length" property, and only then if you haven't found a string, begin the recursion check.
see jsfiddle example here:
http://jsfiddle.net/38d15z4o/
var construct_id = "#ecommerce_form_";
// function to traverse json objects given back from Serializer class
function process(callback, id) {
var key;
for (key in callback) {
// Handle the end - we found a string
if (typeof callback[key] == "string") {
var field_id = construct_id + id + key;
var err_msg = callback[key][0];
$(field_id).tooltip('destroy');
$(field_id).tooltip({'title': err_msg});
$(field_id).closest('div[class="form-group"]').addClass('has-error');
console.log(field_id, ":", err_msg);
}
// Handle the objects and arrays by recursing.
else {
process(callback[key], id + key + "_");
}
}
}
NOTE: for the error message, you are only showing the first letter of the string, I think you meant to put: err_msg = callback[key] not err_msg = callback[key][0].
Why don't you check for
typeof callback[key] === 'array'
Instead checking the length property?
I have tried to write an utility function that can convert my custom data (data Sencha Touch stores use) to JSON format and I am almost done but it fails with complex data coming from twitter API but works fine with simple type of data.
Custom Data
var items = [];
for (var i = 0; i < 10; i++) {
var item = {};
var data = {};
data.prop1 = "123456789";
data.prop2 = "Some Name";
data.prop3 = "Some Date and Time";
item.data = data;
items.push(item);
}
Now above data can be accessed in a loop and can be converted to JSON with following function.
function toJSON(items) {
var jsonString = "[";
for (var i = 0; i < items.length; i++) {
var item = items[i];
jsonString += "{";
for (var propertyName in item.data) {
jsonString += '"' + propertyName + '":' + '"' + item.data[propertyName] + '",';
}
if (jsonString.substr(jsonString.length - 1, 1) === ",") {
jsonString = jsonString.substr(0, jsonString.length - 1);
}
jsonString += "},";
}
if (jsonString.substr(jsonString.length - 1, 1) === ",") {
jsonString = jsonString.substr(0, jsonString.length - 1);
}
jsonString += "]";
return jsonString;
}
The question is if I am doing the encoding thing right?
You can see these fiddle to get real time experience http://jsfiddle.net/WUMTF/ and http://senchafiddle.com/#gxtZ9
Is there any reason why you don't just use the native JSON.stringify() method, or the (wrapped) versions provided by your favorite JavaScript / AJAX library? They will be more robust, tested, secure, and better performing. (Most of the library versions will simply call the browser's native methods if available.)
Your toJSON implementation may be working for your simple test data, but is failing for more complex types of data for many reasons, but most probably most significantly, because it fails to account for any type of nesting. It assumes that the top level is always an array, and that each element in the array only has properties one level deep. Take a look at https://github.com/douglascrockford/JSON-js/blob/master/json.js . This is the implementation provided by Douglas Crockford, the "father" of JSON. Pretty much everything shown there is required for a valid implementation. Unfortunately, the odds are against you if you think that you can easily and simply recreate this in a short amount of time (short of copy and paste).
I'm looking to loop through a JSON array and display the key and value.
It should be a simplified version of the following post, but I don't seem to have the syntax correct: jQuery 'each' loop with JSON array
I also saw the post Get name of key in key/value pair in JSON using jQuery?, but it also seemed like lots of code for a simple activity.
This illustrates what I'm looking for (but it doesn't work):
var result = '{"FirstName":"John","LastName":"Doe","Email":"johndoe#johndoe.com","Phone":"123 dead drive"}';
$.each(result, function(k, v) {
//display the key and value pair
alert(k + ' is ' + v);
});
There is no mandatory jQuery requirement, but it is available. I can also restructure the JSON if it cuts down the required code.
You have a string representing a JSON serialized JavaScript object. You need to deserialize it back to a JavaScript object before being able to loop through its properties. Otherwise you will be looping through each individual character of this string.
var resultJSON = '{"FirstName":"John","LastName":"Doe","Email":"johndoe#johndoe.com","Phone":"123 dead drive"}';
var result = $.parseJSON(resultJSON);
$.each(result, function(k, v) {
//display the key and value pair
alert(k + ' is ' + v);
});
Live demo.
var obj = $.parseJSON(result);
for (var prop in obj) {
alert(prop + " is " + obj[prop]);
}
You can get the values directly in case of one array like this:
var resultJSON = '{"FirstName":"John","LastName":"Doe","Email":"johndoe#johndoe.com","Phone":"123 dead drive"}';
var result = $.parseJSON(resultJSON);
result['FirstName']; // return 'John'
result['LastName']; // return ''Doe'
result['Email']; // return 'johndoe#johndoe.com'
result['Phone']; // return '123'
The following should work for a JSON returned string. It will also work for an associative array of data.
for (var key in data)
alert(key + ' is ' + data[key]);
Parse the JSON string and you can loop through the keys.
var resultJSON = '{"FirstName":"John","LastName":"Doe","Email":"johndoe#johndoe.com","Phone":"123 dead drive"}';
var data = JSON.parse(resultJSON);
for (var key in data)
{
//console.log(key + ' : ' + data[key]);
alert(key + ' --> ' + data[key]);
}
The best and perfect solution for this issue:
I tried the jQuery with the Ajax success responses, but it doesn't work so I invented my own and finally it works!
Click here to see the full solution
var rs = '{"test" : "Got it perfect!","message" : "Got it!"}';
eval("var toObject = "+ rs + ";");
alert(toObject.message);