Why is JSON outputting out of order? - javascript

I'm am trying to get a list of weather information for 8 locations. I'm using a weather API that accepts longitude and latitude and spits back json output with the weather info for that location. I feed the coords in order 0->7 but when json processes the data it comes back in a seemingly random order. I assume it's because some process faster than others and json is outputing what it gets back as it gets it. The output is correct, only the order is wrong.
var loc = null;
var body = "";
var campuses = new Array(8);
campuses[0] = "34.47242,-84.42489,1";
campuses[1] = "33.81488,-84.62048,2";
campuses[2] = "34.27502,-84.46976,3";
campuses[3] = "33.92987,-84.55065,4";
campuses[4] = "34.03433,-84.46723,5";
campuses[5] = "34.08362,-84.67115,6";
campuses[6] = "33.91124,-84.82634,7";
campuses[7] = "34.10409,-84.51804,8";
function getWeather(campusArray)
{
body += '<p class="topTitle">Campus Weather</p>';
var cSplit = new Array();
cSplit = campusArray.split(',');
var loc = "http://www.worldweatheronline.com/feed/weather.ashx?q="+cSplit[0]+","+cSplit[1]+"&format=json&num_of_days=2&key=0a05fff921162948110401&callback=?";
$('#content').html('asdf');
$.getJSON(loc,function(js)
{
var data = js.data;
var humidity = data.current_condition[0].humidity;
var tempF = data.current_condition[0].temp_F;
var iconDESC = data.current_condition[0].weatherDesc[0].value;
var iconURL = data.current_condition[0].weatherIconUrl[0].value;
var windDir = data.current_condition[0].winddir16Point;
var windSpeed = data.current_condition[0].windspeedMiles;
var tempMaxF = data.weather[0].tempMaxF;
var tempMinF = data.weather[0].tempMinF;
body += '<p class="title">'+cSplit[2]+'</p>'+
'<span class="body">'+tempF+
' '+windSpeed+
'<img src="'+iconURL+'" /></span>';
$('#content').html(body);
});
}
getWeather(campuses[0]);
getWeather(campuses[1]);
getWeather(campuses[2]);
getWeather(campuses[3]);
getWeather(campuses[4]);
getWeather(campuses[5]);
getWeather(campuses[6]);
getWeather(campuses[7]);
I have also tried it as $.ajax
var loc = null;
var body = "";
var campuses = new Array(8);
campuses[0] = "34.47242,-84.42489,1";
campuses[1] = "33.81488,-84.62048,2";
campuses[2] = "34.27502,-84.46976,3";
campuses[3] = "33.92987,-84.55065,4";
campuses[4] = "34.03433,-84.46723,5";
campuses[5] = "34.08362,-84.67115,6";
campuses[6] = "33.91124,-84.82634,7";
campuses[7] = "34.10409,-84.51804,8";
function getWeather(campusArray)
{
body += '<p class="topTitle">Campus Weather</p>';
var cSplit = new Array();
cSplit = campusArray.split(',');
var loc = "http://www.worldweatheronline.com/feed/weather.ashx?q="+cSplit[0]+","+cSplit[1]+"&format=json&num_of_days=2&key=0a05fff921162948110401&callback=?";
$.ajax({
url: loc,
async: true,
dataType: "json",
success: function(js)
{
var data = js.data;
var humidity = data.current_condition[0].humidity;
var tempF = data.current_condition[0].temp_F;
var iconDESC = data.current_condition[0].weatherDesc[0].value;
var iconURL = data.current_condition[0].weatherIconUrl[0].value;
var windDir = data.current_condition[0].winddir16Point;
var windSpeed = data.current_condition[0].windspeedMiles;
var tempMaxF = data.weather[0].tempMaxF;
var tempMinF = data.weather[0].tempMinF;
body += '<p class="title">'+cSplit[2]+'</p>'+
'<span class="body">'+tempF+
' '+windSpeed+
'<img src="'+iconURL+'" /></span>';
$('#content').html(body);
}
});
}
getWeather(campuses[0]);
getWeather(campuses[1]);
getWeather(campuses[2]);
getWeather(campuses[3]);
getWeather(campuses[4]);
getWeather(campuses[5]);
getWeather(campuses[6]);
getWeather(campuses[7]);
EDIT:
example of json output:
{ "data": { "current_condition": [ {"cloudcover": "100", "humidity": "93", "observation_time": "04:04 PM", "precipMM": "0.0", "pressure": "1009", "temp_C": "2", "temp_F": "36", "visibility": "8", "weatherCode": "116", "weatherDesc": [ {"value": "Mist" } ], "weatherIconUrl": [ {"value": "http:\/\/www.worldweatheronline.com\/images\/wsymbols01_png_64\/wsymbol_0006_mist.png" } ], "winddir16Point": "WNW", "winddirDegree": "290", "windspeedKmph": "7", "windspeedMiles": "4" } ], "request": [ {"query": "Lat 34.47 and Lon -84.42", "type": "LatLon" } ], "weather": [ {"date": "2011-01-06", "precipMM": "9.3", "tempMaxC": "7", "tempMaxF": "45", "tempMinC": "2", "tempMinF": "35", "weatherCode": "113", "weatherDesc": [ {"value": "Sunny" } ], "weatherIconUrl": [ {"value": "http:\/\/www.worldweatheronline.com\/images\/wsymbols01_png_64\/wsymbol_0001_sunny.png" } ], "winddir16Point": "WNW", "winddirDegree": "293", "winddirection": "WNW", "windspeedKmph": "20", "windspeedMiles": "13" }, {"date": "2011-01-07", "precipMM": "0.0", "tempMaxC": "6", "tempMaxF": "44", "tempMinC": "0", "tempMinF": "31", "weatherCode": "116", "weatherDesc": [ {"value": "Partly Cloudy" } ], "weatherIconUrl": [ {"value": "http:\/\/www.worldweatheronline.com\/images\/wsymbols01_png_64\/wsymbol_0002_sunny_intervals.png" } ], "winddir16Point": "WNW", "winddirDegree": "286", "winddirection": "WNW", "windspeedKmph": "25", "windspeedMiles": "16" } ] }}

You need to modify the getJSON callback you are using to be recursive:
var loc = null, body = "", var campuses = [
"34.10409,-84.51804,8", "33.91124,-84.82634,7", "34.08362,-84.67115,6",
"34.03433,-84.46723,5", "33.92987,-84.55065,4", "34.27502,-84.46976,3",
"33.81488,-84.62048,2", "34.47242,-84.42489,1"
]; // notice they are sorted backwards
function getWeather(campusArray) {
var cSplit = [], loc;
body += '<p class="topTitle">Campus Weather</p>';
cSplit = campusArray.pop().split(','); // popping the array removes it
// from the length
/* truncated for brevity. Put your additional code here. */
$.getJSON(loc, function(js) {
/* truncated for brevity. Put your code here. */
if (campusArray.length) {
getWeather(campusArray);
}
});
}
getWeather(campuses);

You could use the Ajax method and specify async: false, which would cause each call to block. The alternative would be to have placeholders for each campus result and to replace that for each as the results are returned, you'd need to extend your getWeather method to accept the target element but that would mean you could still use the async Ajax approach which would be better for your users.

Related

Postman JSON parse response body arrays inside arrays

I have this JSON Response from API call
[
{
"id": 20599,
"name": "Deliver",
"options": [
{
"id": 63775,
"name": "Item",
"dataType": "SelectMultiOption",
"required": false,
"options": [
{
"id": 426,
"name": "Towels"
},
{
"id": 427,
"name": "Toothbrush"
},
{
"id": 428,
"name": "Pillow"
}
]
}
]
}
]
I am using this code to get the id of the service "Deliver"
var data = JSON.parse(responseBody);
var loop_count = 0
for (count = 0; count < data.length; count++)
{
if (data[count].name == "Deliver")
{
var job_id = data[count].id;
postman.setEnvironmentVariable("service_id", job_id);
}
}
The questions are:
How can I get value from array "options", I need to get the "id":
63775 and store as "item_id" and the "name":"Item" as "item_name" postman variables.
Then I need to select the "options" nested in record
"Item" and select the option "name": "Toothbrush" and store in postman
variable "svc_optn_optn_name" and it's "id" stored in
"svc_optn_optn_id"
Here I am giving my own suggestion for your problem with few lines of code. I am not sure, how are you going to use these values. I also don't know if the outer options array will always have 1 item or more. I have just tried to satisfy your questions.
Please ask/comment, if you have more doubts or I am wrong.
I have created a function getAllPostmanDataFrom(obj) which takes object as parameter which is the value of data[count], gathers necessary info in other object postmanObj and returns it to the caller.
function getAllPostmanDataFrom(obj) {
const item_id = obj.options[0].id;
const item_name = obj.options[0].name;
const svc_optn_optn_name = obj.options[0].options[1].name;
const svc_optn_optn_id = obj.options[0].options[1].id;
const postmanObj = {item_id, item_name, svc_optn_optn_id, svc_optn_optn_name}; // Return object
return postmanObj;
}
var data = [
{
"id": 20599,
"name": "Deliver",
"options": [
{
"id": 63775,
"name": "Item",
"dataType": "SelectMultiOption",
"required": false,
"options": [
{
"id": 426,
"name": "Towels"
},
{
"id": 427,
"name": "Toothbrush"
},
{
"id": 428,
"name": "Pillow"
}
]
}
]
}
]
var count = 0;
var obj = data[count];
var postmanObj = getAllPostmanDataFrom(obj);
//var {item_id, item_name, svc_optn_optn_id} = postmanObj;
console. log(postmanObj)
/*
console.log(item_id);
console.log(item_name);
console.log(svc_optn_optn_id);
console.log(svc_optn_optn_name);
*/
Finally, you can use values contained in postmanObj as follows:.
postman.setEnvironmentVariable("item_id", postmanObj.item_id);
postman.setEnvironmentVariable("item_name", postmanObj.item_name);
And so on.
This is the solution
var data = JSON.parse(responseBody);
variable named as data
var loop_count = 0
for (count = 0; count < data.length; count++)
{
if (data[count].name == "Deliver")
{
var job_id = data[count].id;
postman.setEnvironmentVariable("service_id", job_id);
var job1_name = data[count].options[0].name;
postman.setEnvironmentVariable("item_name", job1_name);
var job2_id = data[count].options[0].id;
postman.setEnvironmentVariable("item_id", job2_id);
var job3_id = data[count].options[0].options[1].id;
postman.setEnvironmentVariable("svc_optn_optn_id", job3_id);
var job4_name = data[count].options[0].options[1].name;
postman.setEnvironmentVariable("svc_optn_optn_name", job4_name);
}
const data = JSON.parse(responseBody);
data.forEach(item => {
console.log(item.id); // deliver object id.
item.options.forEach(option => {
console.log(`Option Id ${option.id}`); // option id
postman.setEnvironmentVariable("service_id", option.id);
option.options(optionItem => {
if(optionItem.name == 'Toothbrush'){
postman.setEnvironmentVariable("svc_optn_optn_name", optionItem.name);
postman.setEnvironmentVariable("svc_optn_optn_id", optionItem.id);
}
});
});
});

Dimple.js doesn't like my Array

I have data.json in this format:
{
"Users": [
{
"userName": "Herbie",
"weigh-in data": [
{ "date": "2016.01.04", "weight": "114.3" },
{ "date": "2016.01.05", "weight": "114.6" },
{ "date": "2016.01.06", "weight": "114.9" }
]
},
{
"userName": "Wayne",
"weigh-in data": [
{ "date": "2016.02.01", "weight": "120.3" },
{ "date": "2016.02.05", "weight": "123.6" },
{ "date": "2016.02.06", "weight": "123.9" }
]
}
]
}
// etc., more user objects
In my application: a selection of a user is made, an ajax call gets this data, I loop thru it to get only the selected user's weigh-in data, and I'm successfully rendering this data to a table.
Now I'm trying to use the same result in a Dimple chart but Dimple evidently doesn't like my chartData array:
var dataObj = JSON.parse(jsonData);
var usersArray = dataObj.Users;
var chartData = [];
// etc. SNIP
for (var obj of usersArray) {
if (obj.userName === selUser) { // weigh-ins of the selected user only
dataRows.innerHTML = "";
for (var i = 0, j = selUserData.length; i < j; i++) {
var dataDate = selUserData[i].date;
var dataWeight = selUserData[i].weight;
chartData.push('{ "User"' + ': ' + '"'+selUser+'", ' + '"Date":' + ' ' + '"'+dataDate+'", ' + '"Weight":' + ' ' + '"'+dataWeight+'" }');
// SNIP: build rows from the data, load up the table, no problem
dataRows.innerHTML += row;
} // selUserData loop
var svg = dimple.newSvg("#chartContainer", 800, 600);
var chart = new dimple.chart(svg, chartData);
chart.setBounds(60, 30, 505, 305);
var x = chart.addCategoryAxis("x", "Date");
x.addOrderRule("Dates");
var y = chart.addCategoryAxis("y", "Weight");
y.addOrderRule("Weights");
var s = chart.addSeries("weigh-ins", dimple.plot.line);
chart.draw();
... which results in a non-chart. However, if I console.log or alert(chartData) and set the result as chartData, i.e.:
var chartData = [
{ "User": "Wayne", "Date": "2016.02.01", "Weight": "180.3" },
{ "User": "Wayne", "Date": "2016.02.05", "Weight": "123.6" },
{ "User": "Wayne", "Date": "2016.02.06", "Weight": "153.9" }
]
... then I get a chart, ergo my confusion.
Any insight greatly appreciated,
Whiskey
You're pushing the JSON into your array as strings not objects, it should be:
chartData.push({ "User": selUser, "Date": dataDate, "Weight": dataWeight });
Which has the added benefit of being much easier to read!

How to parse nested JSON in Javascript?

I am trying to parse and show JSON data (product catalog) using XMLHttpRequest method. I am able to display the brands and their names, but not able to showcase list of products progmatically.
Here is the sample JSON request:
{
"products": {
"laptop": [{
"brand": "sony",
"price": "$1000"
}, {
"brand": "acer",
"price": "$400"
}],
"cellphone": [{
"brand": "iphone",
"price": "$800"
}, {
"brand": "htc",
"price": "$500"
}],
"tablets": [{
"brand": "iPad",
"price": "$800"
}, {
"brand": "htc-tab",
"price": "$500"
}]
}
}
Right now I am using following code to show data in tabluar form:
function loadJSON() {
var data_file = "http://localhost/AJAX/productcatalog.json";
var http_request = new XMLHttpRequest();
http_request.onreadystatechange = function () {
if ((http_request.readyState == 4) && (http_request.status == 200)) {
// Javascript function JSON.parse to parse JSON data
var jsonObj = JSON.parse(http_request.responseText);
data = '<table border="2"><tr><td>Type</td><td>Brand</td><td>Price</td></tr>';
var i = 0;
debugger;
for (i = 0; i < jsonObj["products"].laptop.length; i++)
{
obj = jsonObj["products"].laptop[i];
data = data + '<tr><td>laptop</td><td>' + obj.brand + '</td><td>' + obj.price + '</td></tr>';
}
for (i = 0; i < jsonObj["products"].cellphone.length; i++)
{
obj = jsonObj["products"].cellphone[i];
data = data + '<tr><td>laptop</td><td>' + obj.brand + '</td><td>' + obj.price + '</td></tr>';
}
for (i = 0; i < jsonObj["products"].tablets.length; i++)
{
obj = jsonObj["products"].tablets[i];
data = data + '<tr><td>laptop</td><td>' + obj.brand + '</td><td>' + obj.price + '</td></tr>';
}
data += '</table>';
document.getElementById("demo").innerHTML = data;
}
}
http_request.open("GET", data_file, true);
http_request.send();
}
Question What is the way to fetch product list , i.e. products, cellphone and tablets ? Right now I have hardcoded that in order to fetch complete list of brands. Please advice. (I want to use plain javascript and not jquery)
Thanks!
It sounds like what you're missing is the "How do I iterate over an object when I don't know all the keys".
An object is a set of key, value pairs. You can use for/in syntax: for( var <key> in <object> ){} to get each key.
For your use case it might be something like:
var products = jsonObject['products'];
for( var productName in products ){
//productName would be "laptop", "cellphone", etc.
//products[productName] would be an array of brand/price objects
var product = products[productName];
for( var i=0; i<product.length; i++ ){
//product[i].brand
//product[i].price
}
}
In practice, I might use something a little less verbose, but this makes it easier to understand what is going on.
To achieve the expected i have used for loop and HTML DOM createElement() Method
var product_catalog = {
"products": {
"laptop": [{
"brand": "sony",
"price": "$1000"
}, {
"brand": "acer",
"price": "$400"
}],
"cellphone": [{
"brand": "iphone",
"price": "$800"
}, {
"brand": "htc",
"price": "$500"
}],
"tablets": [{
"brand": "iPad",
"price": "$800"
}, {
"brand": "htc-tab",
"price": "$500"
}]
}
};
var output = document.querySelector('#product tbody');
function build(JSONObject) {
/**get all keys***/
var keys = Object.keys(JSONObject);
/**get all subkeys***/
var subkeys = Object.keys(JSONObject[keys]);
console.log(subkeys);
/**loop sub keys to build HTML***/
for (var i = 0, tr, td; i < subkeys.length; i++) {
tr = document.createElement('tr');
td = document.createElement('td');
td.appendChild(document.createTextNode(subkeys[i]));
tr.appendChild(td);
output.appendChild(tr);
}
};
build(product_catalog);
HTML:
Coepen URL for reference- http://codepen.io/nagasai/pen/xOOqMv
Hope this works for you :)
Look at this example:
var x = data.key1.children.key4;
var path = "data";
function search(path, obj, target) {
for (var k in obj) {
if (obj.hasOwnProperty(k))
if (obj[k] === target)
return path + "['" + k + "']"
else if (typeof obj[k] === "object") {
var result = search(path + "['" + k + "']", obj[k], target);
if (result)
return result;
}
}
return false;
}
//Then for evry node that you need you can call the search() function.
var path = search(path, data, x);
console.log(path); //data['key1']['children']['key4']
I think this is what you're asking about, you can use Object.keys to get the properties of an object, then loop through them afterward.
var data = {
"products": {
"laptop": [{
"brand": "sony",
"price": "$1000"
}, {
"brand": "acer",
"price": "$400"
}],
"cellphone": [{
"brand": "iphone",
"price": "$800"
}, {
"brand": "htc",
"price": "$500"
}],
"tablets": [{
"brand": "iPad",
"price": "$800"
}, {
"brand": "htc-tab",
"price": "$500"
}]
}
}
var typesOfProducts = Object.keys(data.products)
console.log(typesOfProducts)
document.getElementById('output').textContent = typesOfProducts.toString()
//Then, to loop through
var i = -1,
len = typesOfProducts.length
function handleProduct(productType) {
console.log("This is the " + productType + " data.")
console.log(data.products[productType])
}
while (++i < len) {
handleProduct(typesOfProducts[i])
}
<div id="output"></div>
It sounds like what you're looking for is just an array of the keys of the "products" object. Example:
Products: ["laptop", "cellphone", "tablets"];
If so, I would just run your json object through javascript's Object.keys() method.
var jsonObj = JSON.parse(http_request.responseText);
var products = Object.keys(jsonObj.products);
// products = ["laptop", "cellphone", "tablets"];

How to parse repetitive string into array of objects in JavaScript?

I have a the attributes of several objects in a single long string, separated by a "|", like this:
branches = "001|lat1|lon1|Name1|002|lat2|lon2|Name2|003|lat3|lon3|Name3|004|lat4|lon4|Name4"
headers = "ID|Latitude|Longitude|Name" //name of attributes
fieldCount = "4" //4 attributes per object
I need to transform that into a propper array of objects in JavaScript, like this:
[
{
"ID": "001",
"latitude": "lat1",
"longitude": "lon1",
"name": "Name1"
},
{
"ID": "002",
"latitude": "lat2",
"longitude": "lon2",
"name": "Name2"
},
{
"ID": "003",
"latitude": "lat3",
"longitude": "lon3",
"name": "Name3"
},
{
"ID": "004",
"latitude": "lat4",
"longitude": "lon4",
"name": "Name4"
}
]
The question is how to accomplish this?
All you need to do is split the strings to create arrays and loop through them popping off the front item from the branches array for each item in the headers array
var branches = "001|lat1|lon1|Name1|002|lat2|lon2|Name2|003|lat3|lon3|Name3|004|lat4|lon4|Name4";
var headers = "ID|Latitude|Longitude|Name";
branches = branches.split("|");
headers = headers.split("|");
var array=[];
while(branches.length){
var x = {};
for(i=0;i<headers.length;i++){
x[headers[i]]=branches.shift();
}
array.push(x);
}
console.log(array);
var branches = "001|lat1|lon1|Name1|002|lat2|lon2|Name2|003|lat3|lon3|Name3|004|lat4|lon4|Name4";
var headers = "ID|Latitude|Longitude|Name"; //name of attributes
var branchArray = branches.split("|");
var headerArray = headers.split("|");
var numFields = headerArray.length; //fieldCount is redundant
var objects = []; //result will be stored here
var currentObj = {};
for(var i = 0; i < branchArray.length; ++i) {
var fieldIndex = i % numFields;
// When we just put in the last field
if(fieldIndex === (numFields - 1)) {
if(currentObj) {
objects.push(currentObj);
currentObj = {};
}
}
currentObj[headerArray[fieldIndex]] = branchArray[i];
}
There are edge cases like when number of fields in branches is not divisible by number of fields in headers but you did not specify clearly how to handle those.

one of JSON values returns unidentified with JavaScript

I need to retrieve email field from JSON with JavaScript.
Here is the code:
"contacts": [
{
"addedAt": 1332358711001,
"vid": 1,
"properties": {
"lastname": {
"value": "Mott"
},
"firstname": {
"value": "Adrian"
}
},
"identity-profiles": [
{
"vid": 1,
"identities": [
{
"type": "EMAIL",
"value": "test-fdfc6c2e-e19e-4138-8201-8342ca333aa1#hubspot.com",
"timestamp": 1332358711715
},
{
"type": "LEAD_GUID",
"value": "f3ebaf07-1c6d-4ada-af31-3559dd8b3027",
"timestamp": 1332358711771
}
]
}
]
}]
The code works with all fields, except when I get to Identities, it returns NULL or unidentified.
var temp = fields.contacts.length;
for (var i=0; i<fields.contacts.length; i++){
var addedAt = fields.contacts[i].addedAt;
var formattedDate = Utilities.formatDate(new Date(addedAt), "GMT", "yyyy-MM-dd");
var lastName = fields.contacts[i].properties.lastname.value;
var firstName = fields.contacts[i].properties.firstname.value;
var vid = fields.contacts[i].vid;
var ip = fields.contacts[i]['identity-profiles'];
var id = ip.identities;
}
var id always returns unidentified. Also doesn't work:
for (var j=0; i<id.length; j++){
if(typeof ['type'] == 'EMAIL'){
var email = id[j].value;
}
};
fields.contacts[i]['identity-profiles'] is an array, it doesn't directly have a identities property.
You may want
var id = ip[0].identities;
or you should iterate over fields.contacts[i]['identity-profiles'] but it's not clear what you precisely want.

Categories