jQuery traverse json recursive - javascript

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?

Related

Converting a badly stringfied json to a json object

I have some data i am pulling from a web service. This is the string
(Body:'3886' MessageProperties [headers={}, timestamp=null,
messageId=null, userId=null, receivedUserId=null, appId=null,
clusterId=null, type=null, correlationId=null,
correlationIdString=null, replyTo=null,
contentType=application/x-java-serialized-object,
contentEncoding=null, contentLength=0, deliveryMode=null,
receivedDeliveryMode=PERSISTENT, expiration=null, priority=0,
redelivered=false, receivedExchange=,
receivedRoutingKey=bottomlesspit, receivedDelay=null, deliveryTag=62,
messageCount=0, consumerTag=amq.ctag-sCwfLaMEqWp2GkFwFrY1yg,
consumerQueue=bottomlesspit])
It looks like json but the key value pairs are almost fine but the most important key which is Body isn't like other keys as the string would tell.
I need to read the value of Body and be able to get the value like this
console.log(d.body);
//This above outputs the string as shown
obj = eval('{' + d.body + '}');
console.log(obj);
var match = "Body";
var val = obj.find( function(item) { return item.key == match } );
console.log(val);
How can i read the value of the key Body?.
Use this regular expression instead of a match Body:
\bBody:'(\d*)'
This will catch the Body number in group 1.
You can write a parser function get string and extract values. A very simple function is here. You can modify it also for all exceptions exist.
var str = `(Body:'3886' MessageProperties [headers={}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=application/x-java-serialized-object, contentEncoding=null, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=bottomlesspit, receivedDelay=null, deliveryTag=62, messageCount=0, consumerTag=amq.ctag-sCwfLaMEqWp2GkFwFrY1yg, consumerQueue=bottomlesspit])`;
function f(inp) {
var index = str.indexOf(inp),
endIndex;
for(var i = index; i < str.length; i ++) {
if(str[i] == ',') {
endIndex = i;
break;
}
}
var output = str.substr(index, endIndex).split('=');
return output;
}
console.log(f('consumerQueue'));
Why not use a regex to match and extract the Body.
Example:
const match = d.body.match(/Body:\'(.+)\'/)
if (match) {
const body = match[1] // This is the value of Body
} else {
// Unable to find Body, handle it here
}

Encode object literal as URL query string in Javascript

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"}

js/jQuery - Converting array to string

The 2 drop downs I'm using to store into local storage are storing as an array.
How could I convert it where if any arrays are detected then convert it and store it as string instead?
Something like this?
if( Object.prototype.toString.call( value ) === '[object Array]' ) {
value.toString();
}
Please see my fiddle:http://jsfiddle.net/3u7Xj/137/
Showing being stored as:http://i.imgur.com/L78kGE7.jpg
local storage function:
save = function () {
$('input, select, textarea').each(function () {
var value = $(this).val();
var name = $(this).attr('name');
if($(this).hasClass('checkers')){
value = $(this).is(":checked")
if(value){
value='on';
}else{
value='off';
}
}
if(this.name.match(/^multiselect_/)){//removes buggy append
return false;
}
console.log('Saving');
console.log(name + ':' + value);
Survey[name] = value;
});
if (localStorage.getObj('Surveys') != null) {
Surveys = localStorage.getObj('Surveys');
}
Surveys[$('#FirstName').val() + '.' + $('#LastName').val()] = Survey; //store in big list
localStorage.setObj('Surveys', Surveys);
}
The easiest way to convert an array to a string is array.join(). Called just like that you get a comma-delimited string that contains all of the elements in the array. If you provide a separator (such as array.join('|')) you get a string that is delimited with the separator you provided. Where this fits into your saving function is up to you.
I would recommend using jQuery.encodeJSON()
http://forum.jquery.com/topic/jquery-encodejson
This way you can store your object as a JSON string.
You can then get your object back using the jQuery.parseJSON() function.
https://api.jquery.com/jQuery.parseJSON/
If i understood it right, i guess this could work:
Use Array.isArray method and then use JSON.stringify to turn the array into a string.
for (var key in this) {
//console.log(key, this[key]); //log to console
if($.isArray(this[key])) {
this[key] = this[key].join(':'); //change array to string separated by :
}
}

jQuery serialize and validate data

I have the following line returned from serializing data
rl=250&first_name=&surname=&email=&phone=&country_id=1&agency_name=&sitename=
I want to loop through these and check if there is an empty field and if there is then I can throw an error.
I can get the index and element but the element is rl=250 or first_name=
How can I check if the element is set or not. I have also tried using serializeArray() but it returns me [Object, Object, Object, Object, Object, Object, Object, Object] which should have the name and value but I do not know how to access these
You need to split this using '&'. Then you should apply for loop and in that loop you again need to split that string with '=' sign. Then if you get second element of loop as blank, you can throw error
serializeArray is a good way.
https://api.jquery.com/serializeArray/
As you can see, it returns arrays of objects so in your case it is something like tihs:
[
{
rl: 250
},
{
first_name: undefined
}
]
After this you can iterate on the array of the objects with for loop on the values.
I found this function by Jack alan
https://stackoverflow.com/a/16215183/1430587
function deparam(query) {
var pairs, i, keyValuePair, key, value, map = {};
// remove leading question mark if its there
if (query.slice(0, 1) === '?') {
query = query.slice(1);
}
if (query !== '') {
pairs = query.split('&');
for (i = 0; i < pairs.length; i += 1) {
keyValuePair = pairs[i].split('=');
key = decodeURIComponent(keyValuePair[0]);
value = (keyValuePair.length > 1) ? decodeURIComponent(keyValuePair[1]) : undefined;
map[key] = value;
}
}
return map;
}
You could do something like this:
$(document).ready( function(e) {
$("#frm-login").submit(function() {
var DATA = $(this).serializeArray();
len = DATA.length,
dataObj = {};
for (i=0; i<len; i++) { // acceesing data array
dataObj[DATA[i].name] = DATA[i].value;
}
if ( !dataObj['user-id'].trim() || !dataObj['user-pass'].trim() ) { //cheking if empty field
alert('empty');
}else{
alert('full');
}
//console.log(DATA);
$.ajax({
type: "POST",
url: 'user-login-process.php',
data: DATA,
success: function(response){
//alert(response); // show response from the php script.
}
});
return false; // avoid to run the actual submit of the form.
});
}); //document

chrome.storage.local.get results in "Undefined" when called

I'm building a chrome extension, and I needed to save some data locally; so I used the Storage API . I got to run the simple example and save the data, but when I integrated it with my application, it couldn't find the data and is giving me "Undefined" result.
Here is my Code:
function saveResults(newsId, resultsArray) {
//Save the result
for(var i = 0; i < resultsArray.length; i++) {
id = newsId.toString() + '-' + i.toString();
chrome.storage.local.set({ id : resultsArray[i] });
}
//Read and delete the saved results
for(var i = 0; i < resultsArray.length; i++) {
id = newsId.toString() + '-' + i.toString();
chrome.storage.local.get(id, function(value){
alert(value.id);
});
chrome.storage.local.remove(id);
}
}
I am not certain what type of data you are saving or how much, but it seems to me that there may be more than one newsId and a resultsArray of varying length for each one. Instead of creating keys for each element of resultsArarry have you considered just storing the entire thing as is. An example of this would be:
chrome.storage.local.set({'results':[]});
function saveResults(newsId, resultsArray) {
// first combine the data into one object
var result = {'newsId':newsId, 'resultsArray':resultsArray};
// next we will push each individual results object into an array
chrome.storage.get('results',function(item){
item.results.push(result);
chrome.storage.set({'results':item.results});
});
}
function getResults(newsId){
chrome.storage.get('results', function(item){
item.results.forEach(function(v,i,a){
if(v.newsId == newsId){
// here v.resultsArray is the array we stored
// we can remove any part of it such as
v.resultsArray.splice(0,1);
// or
a.splice(i,1);
// to remove the whole object, then simply set it again
chrome.storage.local.set({'results':a});
}
});
});
}
This way you don't need to worry about dynamically naming any fields or keys.
First of All thanks to Rob and BreadFist and all you guys. I found out why my code wasn't working.
Storage.Set doesn't accept the key to be an 'integer' and even if you try to convert that key to be a 'string' it won't work too. So I've added a constant character before each key and it worked. Here's my code.
function saveResults(Id, resultsArray) {
var key = Id.toString();
key = 'a'.key;
chrome.storage.local.set({key : resultsArray});
}
function Load(Id) {
var key = Id.toString();
key = 'a'.key;
chrome.storage.local.get(key, function(result){
console.debug('result: ', result.key);
});
}

Categories

Resources