How can one iterate with this JSON response file - javascript

As said above, I don't know how to use this kind of JSON response from my server-side php which I got by using this code echo json_encode(array_merge($outp, $outp2));
[
{
"stuid":"12",
"stuname":"Velino Meratis",
"stucourse":"BSIT",
"stustat":"0",
"stulyear":"4",
"stulog":"feb 16 2017"
},
{
"stuid":"13",
"stuname":"Alana Melker",
"stucourse":"BSCE",
"stustat":"1",
"stulyear":"5",
"stulog":"feb 16 2017"
},
{
"stuid":"12",
"cname":"InfoTech000",
"clog":"1"
},
{
"stuid":"12",
"cname":"InfoTech001",
"clog":"2"
},
{
"stuid":"12",
"cname":"C101",
"clog":"3"
},
{
"stuid":"13",
"cname":"CE000",
"clog":"4"
},
{
"stuid":"13",
"cname":"CE001",
"clog":"5"
},
{
"stuid":"13",
"cname":"C101",
"clog":"6"
}
]
If I use this code in my client side javascript
if (this.readyState == 4 && this.status == 200) {
students = JSON.parse(this.responseText);
students.forEach(function(item){
console.log(item.stuid);
x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.cname + "<br>";
});
}
it just ends up giving me this:-
12 Velino Meratis
undefined
13 Alana Melker
undefined
Somehow I can iterate the stuid and the stunamebut it won't allow them to contain the cname as an array with them.
How can I turn that into something like this:-
12 Velino Meratis
InfoTech000, InfoTech001, C101
13 Alana Melker
CE000, CE001, C101
Can someone Help and Elaborate on this?

You can check if the array contains the key or not, that way you will be saved from "undefined" error.
You can do it this way
if(item.hasOwnProperty('cname'))
{
console.log(item.cname);
}
You can use this for stuname or other keys also.

You need to merge student objects in your array by unique IDs. One way to do this is to add new stuids to an array and merge it with subsequent items with same stuid. Once you have array of unique students, you can proceed with other goals.
if (this.readyState == 4 && this.status == 200) {
var students_raw = JSON.parse(this.responseText);
var students = [];
students_raw.forEach(function(item){
var existing = students.find($item => item.stuid === $item.stuid);
if (existing) {
existing = Object.assign({}, existing, item);
} else {
students.push(item);
}
});
// your print loop
students.forEach(function(item) {
var x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.cname + "<br>";
});
}
Please note: Array.reduce() and Object.assign() are not supported widely. you may need to polyfill these methods

NOTE: This answer assumes you're willing and able to change the data coming from PHP
Credit where credit is due, this is an extension of #Magnus Eriksson's comment.
It would be preferable to keep the relevant data associated with each other. You should get better flexibility with well-formed data. Ideally, you should do this server side and present the data to the client already well formatted.
You should try and achieve something similar to the following for your output:
[{
"stuid": "12",
"stuname": "Velino Meratis",
"stucourse": "BSIT",
"stustat": "0",
"stulyear": "4",
"stulog": "feb 16 2017",
"classes": [{
"cname": "InfoTech000",
"clog": "1"
}, {
"cname": "InfoTech001",
"clog": "2"
}, {
"cname": "C101",
"clog": "3"
}]
}, {
"stuid": "13",
"stuname": "Alana Melker",
"stucourse": "BSCE",
"stustat": "1",
"stulyear": "5",
"stulog": "feb 16 2017",
"classes": [{
"cname": "CE000",
"clog": "4"
}, {
"cname": "CE001",
"clog": "5"
}, {
"cname": "C101",
"clog": "6"
}]
}];
Note I've used classes as the property name as it appears we are working with Courses and their classes.
Your javascript will now look like:
if (this.readyState == 4 && this.status == 200) {
students = JSON.parse(this.responseText);
students.forEach(function(item){
console.log(item.stuid);
x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.classes.map(function(elem){
return elem.cname;}).join(",") + "<br>";
});
}
Note the map function won't work in IE8 and lower.
Now for a working example:
var students = [{
"stuid": "12",
"stuname": "Velino Meratis",
"stucourse": "BSIT",
"stustat": "0",
"stulyear": "4",
"stulog": "feb 16 2017",
"classes": [{
"cname": "InfoTech000",
"clog": "1"
}, {
"cname": "InfoTech001",
"clog": "2"
}, {
"cname": "C101",
"clog": "3"
}]
}, {
"stuid": "13",
"stuname": "Alana Melker",
"stucourse": "BSCE",
"stustat": "1",
"stulyear": "5",
"stulog": "feb 16 2017",
"classes": [{
"cname": "CE000",
"clog": "4"
}, {
"cname": "CE001",
"clog": "5"
}, {
"cname": "C101",
"clog": "6"
}]
}];
students.forEach(function(item){
console.log(item.stuid);
x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.classes.map(function(elem){
return elem.cname;}).join(",") + "<br>";
});
<div id="demo"></div>
As mentioned in other answers and comments, the issue with your existing code, is not all objects in your json array have the property you're referencing.

You can try like this once also
HTML
<div id="result"></div>
SCRIPT
var dataJSON = [
{
"stuid":"12",
"stuname":"Velino Meratis",
"stucourse":"BSIT",
"stustat":"0",
"stulyear":"4",
"stulog":"feb 16 2017"
},
{
"stuid":"13",
"stuname":"Alana Melker",
"stucourse":"BSCE",
"stustat":"1",
"stulyear":"5",
"stulog":"feb 16 2017"
},
{
"stuid":"12",
"cname":"InfoTech000",
"clog":"1"
},
{
"stuid":"12",
"cname":"InfoTech001",
"clog":"2"
},
{
"stuid":"12",
"cname":"C101",
"clog":"3"
},
{
"stuid":"13",
"cname":"CE000",
"clog":"4"
},
{
"stuid":"13",
"cname":"CE001",
"clog":"5"
},
{
"stuid":"13",
"cname":"C101",
"clog":"6"
}
] ;
var arr = {};
for(var i = 0 ; i< dataJSON.length ; i++){
var ele = dataJSON[i];
if(arr[ ele.stuid ]==undefined){
arr[ ele.stuid ] = {};
}
arr[ ele.stuid ]['stuid'] = ele.stuid;
if(ele.stuname!=undefined){
arr[ ele.stuid ]['stuname'] = ele.stuname;
}
if(arr[ ele.stuid ]['cname'] == undefined){
arr[ ele.stuid ]['cname'] = [];
}
if(ele.cname!=undefined){
arr[ ele.stuid ]['cname'].push(ele.cname);
}
}
var str = '';
for(var key in arr){
var obj = arr[key];
str += obj['stuid'] +" "+obj['stuname']+'<br/>';
str += obj['cname'].toString()+'<br/>';
}
document.getElementById("result").innerHTML = str;
Thanks,

Related

Concatenate strings within array of objects

I have the array of objects as below. I want to loop through it and get Closed property values. It should be a concatenation of all the values found in each object.
For e.g. in below case, i want final result as 121212 since it has 12 in all the 3 objects.
const data = [
{
"personId": "1208007855",
"details": {
"Closed": "12"
}
},
{
"personId": "1559363884",
"details": {
"Closed": "12"
}
},
{
"personId": "973567318",
"details": {
"Closed": "12"
}
}
]
can someone let me know how to achieve this. I tried this way but couldnt succeed in achieving the result. I could only get the value of first object. Not sure how i can concatenate and store next values in this loop
There might be a situation where some objects might not have Closed property.
const totalClosed = data.forEach(function (arrayItem) {
const x = arrayItem.details.Closed;
console.log(x);
});
Try the following:
const data = [
{
"personId": "1208007855",
"details": {
"Closed": "12"
}
},
{
"personId": "1559363884",
"details": {
"Closed": "12"
}
},
{
"personId": "973567318",
"details": {
"Closed": "12"
}
}
];
result = '';
for (let i in data) {
result += data[i].details.Closed
}
You can use the .reduce function:
data.reduce((accumulator, item) => accumulator += item.details.Closed, '')
=> 121212
Using foreach exactly the same way you were trying:
const data = [
{
personId: '1208007855',
details: {
Closed: '12'
}
},
{
personId: '1559363884',
details: {
Closed: '12'
}
},
{
personId: '973567318',
details: {
Closed: '12'
}
}
];
let totalClosed = '';
data.forEach(function (arrayItem) {
totalClosed = totalClosed + arrayItem.details.Closed;
});
console.log(totalClosed);
In functional way, using reduce
const data = [
{
"personId": "1208007855",
"details": {
"Closed": "12",
"Analyze": "10"
}
},
{
"personId": "1559363884",
"details": {
"Closed": "12",
"Analyze": "10"
}
},
{
"personId": "973567318",
"details": {
"Closed": "12",
"Analyze": "10"
}
}
]
const { Closed, Analyze } = data.reduce((acc, cur) => {
acc.Closed += cur?.details?.Closed ?? ''
acc.Analyze += cur?.details?.Analyze ?? ''
return acc
}, { Closed: "", Analyze: "" })
console.log({ Closed, Analyze })
let str = "";
for(let i=0; i<data.length;i++){
str+= data[i].details.Closed;
}
console.log(str);
Also, with forEach, the elements might not be processed in the same order (0 to n) and you may find different results than you expect.
If you want a string and have an array, the best method is reduce:
const totalClosed = data.reduce(function (accumulator, currentVal) {
const closed = currentVal.details.Closed || '';
return accumulator + closed;
}, '');
let str = ''
const totalClosed = data.forEach(function (arrayItem) {
if(arrayItem.details.Closed){
str += arrayItem.details.Closed;
}
});
console.log(str)
You can create an empty string and add to it if the closed field exists, if there is another condition in 'Closed' you can check there in the if statement.
You can reduce the data entries by destructuring the entry in the reducer and concatenating the Closed value to the running res (result). You can use the nullish-coalescing operator (??) to use an empty string instead of undefined when concatenating.
const data = [
{ "personId": "1208007855" , "details": { "Closed": "12" } },
{ "personId": "1559363884" , "details": { "Closed": "12" } },
{ "personId": "0000000000" , "details": { "Open" : "8" } }, // New!
{ "personId": "973567318" , "details": { "Closed": "12" } }
];
const value = data.reduce((res, { details: { Closed } }) => res + (Closed ?? ''), '');
console.log(value);
If you want to implement using loops Try Using:
const data = [
{
"personId": "1208007855",
"details": {
"Closed": "12"
}
},
{
"personId": "1559363884",
"details": {
"Closed": "12"
}
},
{
"personId": "973567318",
"details": {
"Closed": "12"
}
}
];
var res= ''
data.forEach((item)=>{if(item.details.Closed){ res += item.details.Closed;}})
console.log(res)
And this can also be done by using higher order functions:
Try using :
data.reduce((res, item) =>{if(item.details.Closed)
res += item.details.Closed;
return res}, '')

Remove Duplicates from Json file using Javascript

I have a json file like below (test.json). I am unsuccessfully trying to parse the test array and remove duplicates of any "name" below
{
"test": [{
"name": "jeb",
"occupation": "teacher"
},
{
"name": "jeb",
"occupation": "writer"
},
{
"name": "bob",
"occupation": "skydiver"
}
]
}
So far, my code is the following:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
var i;
var test= myObj.test.length;
for (i=0; i<=myObj.test.length; i++) {
var name = myObj.test[i].name;
var occupation = myObj.test[i].occupation;
console.log(name + " and " + occupation)
}
}
}
xmlhttp.open("GET", "test.json", true);
xmlhttp.send();
and it prints out:
jeb and teacher
jeb and writer
bob and skydiver
I would like the end result to be be:
jeb and teacher, writer
bob and skydiver
Any help is appreciated. Thank you!
It would probably be best to reduce into an object indexed by name, whose value is an array of occupations, and then once the object is created, you can iterate over it and print the occupations of each name:
const obj = {
"test": [{
"name": "jeb",
"occupation": "teacher"
},{
"name": "jeb",
"occupation": "writer"
},{
"name": "bob",
"occupation": "skydiver"
}]
};
const namesByOccupation = obj.test.reduce((a, { name, occupation }) => {
if (!a[name]) a[name] = [];
a[name].push(occupation);
return a;
}, {});
Object.entries(namesByOccupation).forEach(([name, occupations]) => {
console.log(name + ' and ' + occupations.join(', '));
});

calculate item length in outer of map

I have a json like this
var person = [{
"name": "john",
"age": 20
}, {
"name": "Samuel",
"age": 10
}, {
"name": "Jin",
"age": 10
}]
My desire output is
age 10 (2)
- Samuel
- Jin
age 20 (1)
- John
I have problem counting the total. I would do
ages.map(doList) //where ages is [10,20]
doList(age) {
persons.filter(p => p.age === age)
.map(p => {
p.name
})
}
but how do print out the length of the age group?
You might change your data structure for easier output like.
var person = [{
"name": "john",
"age": 10
}, {
"name": "Samuel",
"age": 10
}, {
"name": "Jin",
"age": 10
}];
let newArray = [];
person.forEach((p) => {
let findPreviousIndex = newArray.findIndex((itm) =>{
return itm.age == p.age;
});
if(findPreviousIndex > -1){
// previous found, push the name
newArray[findPreviousIndex].names.push(p.name);
}else{
// not found. create a new object and push it
newArray.push({
"age" : p.age,
"names" : [].concat(p.name)
})
}
});
console.log(newArray);
Now, its easy to print your grouped data and easy to find length.
Here's one way to produce the desired output, first using .reduce() to set up a result object with a property for each age that is an array of names for that age, then mapping over the properties of result to create a formatted string that gives the specific format in the question:
var person = [{
"name": "john",
"age": 20
}, {
"name": "Samuel",
"age": 10
}, {
"name": "Jin",
"age": 10
}]
var result = person.reduce((a, c) => {
(a[c.age]||(a[c.age]=[])).push(c.name)
return a
}, {})
console.log(result)
var formatted = Object.keys(result)
.map(k=>`age ${k} (${result[k].length})\n${result[k].map(n => `- ${n}`).join('\n')}`)
.join('\n\n')
console.log(formatted)
var person = [{
"name": "john",
"age": 20
}, {
"name": "Samuel",
"age": 10
}, {
"name": "Jin",
"age": 10
}];
// create a map where the key is the person's age and the value is a list of names
var ageMap = person.reduce(function(result, p) {
var key = p.age;
var name = p.name;
if (result[key]) {
result[key].push(name);
} else {
result[key] = [name];
}
return result;
}, {});
// traverse the map and print the names of people grouped by age
Object.keys(ageMap).forEach(function(key) {
var value = ageMap[key];
console.log("age " + key + " (" + value.length + ")");
value.forEach(function(name) {
console.log("- " + name);
});
console.log("");
});
JSFiddle: https://jsfiddle.net/njcms8rj/

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"];

difficulties in JSON forming

This is the code to form a JSON that a server expects. But there are some problems though
<!DOCTYPE html>
<html>
<body>
<script language="javascript" type="text/javascript">
<!--
//var acc = {};
var x = 10;
var y = 20;
var z = 30;
var output = [];
output[0] = {
name: "Accelerometer_X",
value: JSON.parse(x), // retrieve x
};
output[1] = {
name: "Accelerometer_Y",
value: JSON.parse(y), // retrieve y
};
output[2] = {
name: "Accelerometer_Z",
value: JSON.parse(z) // retrieve z
};
var record = [];
record[0] = {
starttime: new Date(),
output: output,
};
var observations = [];
observations[0] = {
sensor: "",
record: record,
};
var fromData = {};
fromData.version = "1.0.1";
fromData.observations = observations;
alert(JSON.stringify(fromData));
console.log(JSON.stringify(fromData));
//-->
</script>
</body>
</html>
The output JSON is:
{
"version": "1.0.1",
"observations": [
{
"sensor": "",
"record": [
{
"starttime": "2014-08-15T16:01:34.711Z",
"output": [
{
"name": "Accelerometer_X",
"value": 10
},
{
"name": "Accelerometer_Y",
"value": 20
},
{
"name": "Accelerometer_Z",
"value": 30
}
]
}
]
}
]
}
But the expected JSON is:
{
"version": "1.0.1",
"observations": [
{
"sensor": "",
"record": [
{
"starttime": "1-JAN-2014 15:30:00 IST",
"output": [
{
"name": "Accelerometer_X",
"value": "10"
},
{
"name": "Accelerometer_Y",
"value": "20"
},
{
"name": "Accelerometer_Z",
"value": "30"
}
]
}
]
}
]
}
The values in expected JSON is within "" ie.
{
"name": "Accelerometer_Z",
"value": "30"
}
But the produced JSON is :
{
"name": "Accelerometer_Z",
"value": 30
}
And there is another problem that is the starttime. The expected starttime format is
1-JAN-2014 15:30:00 IST
The produced starttime is:
2014-08-15T16:01:34.711Z
I do not know how to change this. Please help me out.
You shouldn't use JSON.parse on the values that you want to put in the object. The JSON.parse method is used to parse a JSON string into an object, but the values are not JSON strings.
Remove the JSON.parse call (as it doesn't change the value), and use the toString method to turn the values into strings:
output[0] = {
name: "Accelerometer_X",
value: x.toString(),
};
output[1] = {
name: "Accelerometer_Y",
value: y.toString(),
};
output[2] = {
name: "Accelerometer_Z",
value: z.toString()
};
There is no build in function that formats the date that way, you would need to make your own. Something like:
function formatDate(d) {
return d.getDate() + '-' + (d.getMonth() + 1) + "-" + d.getFullYear() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds() + " IST";
}
Usage:
record[0] = {
starttime: formatDate(new Date()),
output: output,
};
This is the code so far working:
<!DOCTYPE html>
<html>
<body>
<script language="javascript" type="text/javascript">
<!--
//var acc = {};
var x = 10;
var y = 20;
var z = 30;
//var accString = JSON.stringify(acc); // that's what you have
var output = [];
output[0] = {
name: "Accelerometer_X",
value: x.toString(), // retrieve x
};
output[1] = {
name: "Accelerometer_Y",
value: y.toString(), // retrieve y
};
output[2] = {
name: "Accelerometer_Z",
value: z.toString() // retrieve z
};
var record = [];
record[0] = {
starttime: new Date(),
output: output,
};
var observations = [];
observations[0] = {
sensor: "",
record: record,
};
var fromData = {};
fromData.version = "1.0.1";
fromData.observations = observations;
alert(JSON.stringify(fromData));
console.log(JSON.stringify(fromData));
//-->
</script>
</body>
</html>
But the time is having problem still now. Anyone to resolve this issue?

Categories