Display nested array data in a click event - javascript

I have this data and I'm displaying the name. But when I click on, in this case Sweden, I want to display additional info. In the code below I just want to display the country code, but this creates four additional <p> tags because of .forEach loop. That's not really what I want.
How would I go about if I just want to display the country code, and what if I wanted to display all the additional info? I'm kinda stuck as of now.
let data = [
{"name": "Swaziland", "code": "SZ"},
{"name": "Sweden",
"info": [
{"code": "SE"},
{"population": "10.2 million"},
{"area": "447 435km"},
{"capital": "Stockholm"},
{"Language": "Swedish"}]
},
{"name": "Switzerland", "code": "CH"},
{"name": "Syrian Arab Republic", "code": "SY"}
]
let output = '<ul class="searchresultCountries">';
let countries = data;
countries.forEach((value) => {
output += '<li>' + value.name + '</li>';
});
output += '</ul>';
document.querySelector('#countries').innerHTML = output;
document.addEventListener('click', (e) => {
data.forEach((item) => {
if(item.name === e.target.textContent) {
if(item.info) {
item.info.forEach((items) => {
let extraInfo = document.createElement("p");
extraInfo.textContent = items.code;
e.target.appendChild(extraInfo);
});
}
}
});
});
ul {
padding: 0;
}
.searchresultCountries li {
list-style-type: none;
border: 1px solid grey;
margin-bottom: 10px;
padding: 5px;
}
<div id="countries"></div>

You should have some kind of button or link upon which clicking you can show/hide the extra information.
You can try the following way:
let data = [
{"name": "Swaziland", "code": "SZ"},
{"name": "Sweden",
"info": [
{"code": "SE"},
{"population": "10.2 million"},
{"area": "447 435km"},
{"capital": "Stockholm"},
{"Language": "Swedish"}]
},
{"name": "Switzerland", "code": "CH"},
{"name": "Syrian Arab Republic", "code": "SY"}
]
let output = '<ul class="searchresultCountries">';
let countries = data;
countries.forEach((value) => {
output += '<li>' + value.name + '</li>';
});
output += '</ul>';
document.querySelector('#countries').innerHTML = output;
document.addEventListener('click', (e) => {
data.forEach((item) => {
if(item.name === e.target.textContent) {
if(item.info) {
let extraInfo = document.createElement("p");
extraInfo.textContent = item.info[0].code;
e.target.appendChild(extraInfo);
if(item.info.length > 1){
let btnExtra = document.createElement("button");
btnExtra.textContent = "Show More";
e.target.appendChild(btnExtra);
btnExtra.addEventListener('click', function(){
let container = document.createElement("div");
if(!document.querySelector('.extra')){
container.classList.add('extra');
item.info.forEach(function(el, i){
if(i > 0){ // skip the first
let extra = document.createElement("p");
extra.textContent = Object.values(el)[0];
container.appendChild(extra);
}
});
e.target.appendChild(container);
btnExtra.textContent = "Show Less";
}
else{
document.querySelector('.extra').remove();
btnExtra.textContent = "Show More";
}
});
}
}
else{
let extraInfo = document.createElement("p");
extraInfo.textContent = item.code;
e.target.appendChild(extraInfo);
}
}
});
});
ul {
padding: 0;
}
.searchresultCountries li {
list-style-type: none;
border: 1px solid grey;
margin-bottom: 10px;
padding: 5px;
}
<div id="countries"></div>

Related

moving the content at the end of a table row

I'm having this issues with the below table in which I want to set the 'view book' link and reserved to be the last in the row, but apparently the x = TABLE_ROW.insertCell(-1) is not working.
I just want to have the link/span at the end of the table row. Shouldn't the -1 argument be enough for this?
Can you please help me identifying what I'm doing wrong?
var data = {
"headings": {
"propBook": "Book",
"propAuthor": "Author",
"propYear": "Year",
},
"items": [{
"fields": {
"propBook": "The Great Gatsby",
"propAuthor": "F Scott Fitzgerald",
"propYear": "1925",
},
"button": {
"name": "View book",
"propURL": "https://google.com"
}
},
{
"fields": {
"propBook": "The Grapes of Wrath",
"propAuthor": "John Steinbeck",
"propYear": "1939",
},
"button": {
"name": "View book",
"propURL": ""
}
},
{
"fields": {
"propBook": "A Wild Sheep Chase",
"propAuthor": "Haruki Murakami",
"propYear": "1982",
},
"button": {
"name": "View book",
"propURL": "https://google.com"
}
}
]
}
const HEADINGS = data.headings;
const ITEMS = data.items;
const TABLE_WRAPPER = document.querySelector('.book-component .table-wrapper');
const TABLE = document.createElement('table');
TABLE.setAttribute('class', 'pagination');
TABLE_WRAPPER.appendChild(TABLE);
for (const field in data) {
const TABLE_ROW = document.createElement('tr');
TABLE_ROW.setAttribute('id', 'myRow');
if (field == 'headings') {
for (const child in HEADINGS) {
const HEADER_CELL = document.createElement('th');
TABLE_ROW.appendChild(HEADER_CELL);
HEADER_CELL.setAttribute('class', 'sort-cta');
HEADER_CELL.innerText = HEADINGS[child];
TABLE.appendChild(TABLE_ROW);
}
} else if (field == 'items') {
for (const child in ITEMS) {
const TABLE_ROW = document.createElement('tr');
let item = ITEMS[child].fields;
let btn = ITEMS[child].button;
if (btn.propURL !== '') {
let link = document.createElement('a');
link.setAttribute('href', btn.propURL);
link.innerHTML = btn.name;
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
} else {
let link = document.createElement('span');
link.innerHTML = 'Reserved';
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
}
for (const row in item) {
const TABLE_DATA = document.createElement('td');
TABLE_ROW.appendChild(TABLE_DATA);
TABLE_DATA.innerText = item[row];
TABLE.appendChild(TABLE_ROW);
}
}
}
}
tr.inactive {
display: none;
}
.table-wrapper {
display: flex;
flex-direction: column-reverse;
}
.pager {
display: flex;
justify-content: center;
padding: 0;
margin-top: 10px;
font-weight: 800;
}
.pager-item.selected {
outline: none;
border-color: #0077cc;
background: #0077cc;
color: #fff;
cursor: default;
}
<div class="book-component">
<div class="table-wrapper">
</div>
</div>
You just should inset cell data first. Then insert the link cell at the end of a table row.
http://jsfiddle.net/u1bvq376/
Here is a sample. Hope to help, my friend :))
for (const field in data) {
const TABLE_ROW = document.createElement('tr');
TABLE_ROW.setAttribute('id', 'myRow');
if (field == 'headings') {
for (const child in HEADINGS) {
const HEADER_CELL = document.createElement('th');
TABLE_ROW.appendChild(HEADER_CELL);
HEADER_CELL.setAttribute('class', 'sort-cta');
HEADER_CELL.innerText = HEADINGS[child];
TABLE.appendChild(TABLE_ROW);
}
} else if (field == 'items') {
for (const child in ITEMS) {
const TABLE_ROW = document.createElement('tr');
let item = ITEMS[child].fields;
let btn = ITEMS[child].button;
// insert the cell data first
for (const row in item) {
const TABLE_DATA = document.createElement('td');
TABLE_ROW.appendChild(TABLE_DATA);
TABLE_DATA.innerText = item[row];
TABLE.appendChild(TABLE_ROW);
}
// then insert the link
if (btn.propURL !== '') {
let link = document.createElement('a');
link.setAttribute('href', btn.propURL);
link.innerHTML = btn.name;
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
} else {
let link = document.createElement('span');
link.innerHTML = 'Reserved';
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
}
}
}
}

Trying to access json content and display in a grid fashion

I have a JSON file having the following content.
{
"rooms":[
{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [
{
"srcname":["DirectTV","AppleTV","Sonos"],
"iconpath":["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png","path2"]
}
],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [
{
"srcname":["Climate","Shades"],
"iconpath":["path1","path2"]
}
],
"hex": "#000"
}
}
]
}
My HTML file Has:
<div class="roww">
<div class="col-md-4 col-sm-6 col-12">
</div>
</div>
I want to display my JSON content in the HTML.
So far I have tried the following.
private initTileGrid():void
{
var col = document.getElementsByClassName("roww")[0];
var outeritems=this.room_list.rooms;
// console.log(outeritems);
for(var i=0;i<outeritems.length;i++){
var tile = document.getElementsByClassName("col-md-4 col-sm-6 col-12 tile no-padding")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
var inneritem=outeritems[i].Settings.Sources.srcname;
console.log(inneritem);
var innerdiv = document.createElement("div");
for(var j=0;j<inneritem.length;j++)
{
console.log("hi")
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem.srcname;
console.log(h5inner);
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
}
I am able to display the description and name from the json but not able to fetch the list of sources.
My final solution should be a grid with number of tiles equal to the number of objects in the JSON, with each tile having a background image from the json and its content.
Can anybody tell me where I am going wrong?
Any help appreciated!
I would suggest and recommend generating your dynamic HTML the following way with Template Literals.
Using Array#map, Array#join and Destructuring assignment
const data = {"rooms":[{"id":"1","name":"living","Description":"The living room","backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw","Settings":{"Sources":[{"srcname":["DirectTV","AppleTV","Sonos"],"iconpath":["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png","path2"]}],"hex":"#000"}},{"id":"2","name":"dining","Description":"The Dining room","backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV","Settings":{"Sources":[{"srcname":["Climate","Shades"],"iconpath":["path1","path2"]}],"hex":"#000"}}]}
const res = data.rooms.map(({name, Description, Settings:{Sources}})=>{
const inner = Sources.map(({srcname})=>{
return srcname.map(src=>`<h5>${src}</h5>`).join("");
}).join("");
return `
<div>
<h5>${Description}</h5>
<p>${name}</p>
<div class="inner">
${inner}
</div>
</div>
`
}).join("");
document.body.innerHTML = res;
body>div{background-color:lightgrey;padding:5px;margin-top:5px}body>div::before{content:"row"}body>div>*{margin-left:10px}h5{background-color:blue;color:white;padding:5px}h5::before{content:"outer h5:: "}p{background-color:purple;color:white;padding:5px}p::before{content:"p:: "}div.inner{padding:5px;background-color:grey}div.inner::before{content:"inner div"}div.inner>h5{background-color:green;color:white}div.inner>h5::before{content:"inner h5:: "}
Unminified CSS:
body > div {
background-color: lightgrey;
padding: 5px;
margin-top: 5px;
}
body > div::before {
content: "row";
}
body > div > * {
margin-left: 10px;
}
h5 {
background-color: blue;
color: white;
padding: 5px;
}
h5::before {
content: "outer h5:: "
}
p {
background-color: purple;
color: white;
padding: 5px;
}
p::before {
content: "p:: ";
}
div.inner {
padding: 5px;
background-color: grey;
}
div.inner::before {
content: "inner div";
}
div.inner > h5 {
background-color: green;
color: white;
}
div.inner > h5::before {
content: "inner h5:: "
}
V_Stack as discussed, this is just the tweak I would do to the sources section of the JSON, moving forward it will make working with a source easier, especially if you add additional properties. Note it is an array of self contained objects now.
{
"rooms": [{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [{
"srcname": "DirectTV",
"iconpath": "src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png"
},
{
"srcname": "AppleTV",
"iconpath": "path2"
},
{
"srcname": "Sonos",
"iconpath": ""
}
],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [{
"srcname": "Climate",
"iconpath": "path1"
},
{
"srcname": "Shades",
"iconpath": "path2"
}
],
"hex": "#000"
}
}
]
}
Try this:
var col = document.getElementsByClassName("roww")[0];
var outeritems = this.room_list.rooms;
// console.log(outeritems);
for (var i = 0; i < outeritems.length; i++) {
var tile = document.getElementsByClassName("col-md-4")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
outeritems[i].Settings.Sources.forEach(source => {
var inneritem = source.srcname;
console.log(inneritem);
var innerdiv = document.createElement("div");
for (var j = 0; j < inneritem.length; j++) {
console.log("hi")
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem[j];
console.log(h5inner);
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
});
}
}
You need to loop through the Settings.Sources and srcname because all of them are arrays
Your main problem starts at this line var inneritem=outeritems[i].Settings.Sources.srcname; Sources is an array so you need to access it like Sources[j] where j is a number within the arrays length.
The inner loop is fine, you just need to loop through Sources properly
I also had to add classes to the tiles class to match your getElementsByClassName query
const room_list = {
"rooms": [{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [{
"srcname": ["DirectTV", "AppleTV", "Sonos"],
"iconpath": ["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png", "path2"]
}],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [{
"srcname": ["Climate", "Shades"],
"iconpath": ["path1", "path2"]
}],
"hex": "#000"
}
}
]
}
var col = document.getElementsByClassName("roww")[0];
var outeritems = room_list.rooms;
// console.log(outeritems);
for (var i = 0; i < outeritems.length; i++) {
var tile = document.getElementsByClassName("col-md-4 col-sm-6 col-12 tile no-padding")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
var inneritems = outeritems[i].Settings.Sources
var innerdiv = document.createElement("div");
for (var j = 0; j < inneritems.length; j++) {
var inneritem = inneritems[j];
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem.srcname;
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
}
<div class="roww">
<div class="col-md-4 col-sm-6 col-12 tile no-padding">
</div>
</div>

javascript object array iteration

I have Json data like below;
let data = [
{
"name": "John Doe",
"position": "Accountant",
"social": ["facebook", "instagram", "youtube", "pinterest"]
},
{
"name": "Michael Schumaher",
"position": "F1 Pilot",
"social": ["facebook", "instagram", "youtube", "pinterest"]
}
];
I need to loop iterate nodes and child arrays called social.
let html = '';
let i;
for ( i = 0; i < data.length; i++) {
let socArr = data[i].social;
socArr.forEach ( function ( item ) {
console.log( item + '/');
});
};
I need to display 'name position social' in the same div, but forEach loop gives me all array data in the json document.
Related to your question, I would assume that you only need two div elements. So for that scenario, I would create two statics div into your html body then feeding them with that loop. See the example below:
let data = [
{
"name": "John Doe",
"position": "Accountant",
"social": ["facebook", "instagram", "youtube", "pinterest"]
},
{
"name": "Michael Schumaher",
"position": "F1 Pilot",
"social": ["facebook", "instagram", "youtube", "pinterest"]
}
];
for (let i = 0; i < data.length; i++) {
document.getElementById('myDiv' + (i + 1)).innerHTML = data[i].name + '<br/>' + data[i].position + '<br/>';
let socArr = data[i].social;
socArr.forEach ( function ( item ) {
document.getElementById('myDiv' + (i + 1)).innerHTML += item + '<br/>';
});
document.getElementById('myDiv' + (i + 1)).innerHTML += '<br/>';
}
<div id="myDiv1"></div>
<div id="myDiv2"></div>
I cannot replicate the behavior you state. You should be able to iterate over each record (element of the array) and then iterate over its values:
let data = getData();
let body = document.querySelector('body')
let fragment = document.createDocumentFragment() // used for performance
let text = (str) => document.createTextNode(str) // used to reduce/simplify code
let br = () => document.createElement('br') // used to reduce/simplify code
data.forEach(rcd => {
// create new div for each record
let div = document.createElement('div')
// iterate over record values
for (let value of Object.values(rcd)) {
div.appendChild(text(value))
div.appendChild(br())
}
// add to fragment
fragment.appendChild(div)
});
// add to DOM
body.appendChild(fragment);
// Data structure is placed in function so logic SO is seen first
function getData() {
return [{
"name": "John Doe",
"position": "Accountant",
"social": ["facebook", "instagram", "youtube", "pinterest"]
},
{
"name": "Michael Schumaher",
"position": "F1 Pilot",
"social": ["facebook", "instagram", "youtube", "pinterest"]
}
]
}
div {
border: 1px solid;
padding: .5rem;
margin: 1em
}

How to Create a menu with JSON fetched from Webserver PHP?

I want to make a mobile application using Cordova for my school homework project, and i need to fetch data from PHP Web Server, me already have JSON for this.
This is the example of my mobile app map :
http://prntscr.com/fhq63c .
This is the looks of my JSON :
Product Category :
[[
{"id":1,"name":"Product 1","created_at":"2017-06-06 08:31:34","updated_at":"2017-06-06 09:16:18"},
{"id":2,"name":"Product 2","created_at":"2017-06-06 09:16:12","updated_at":"2017-06-06 09:16:12"},
{"id":3,"name":"Product 3","created_at":"2017-06-06 09:16:24","updated_at":"2017-06-06 09:16:24"}
]]
Package Cateogry :
[[
{"id":1,"product_id":"1","name":"Package 1-1","jumlah_user":"1","created_at":"2017-06-06 09:34:11","updated_at":"2017-06-06 09:34:11"},
{"id":2,"product_id":"1","name":"Package 1-2","jumlah_user":"1","created_at":"2017-06-06 09:35:49","updated_at":"2017-06-06 10:03:43"},
{"id":3,"product_id":"2","name":"Package 2-1","jumlah_user":"1","created_at":"2017-06-07 03:03:35","updated_at":"2017-06-07 03:03:35"},
{"id":4,"product_id":"2","name":"Package 2-2","jumlah_user":"1","created_at":"2017-06-07 03:30:11","updated_at":"2017-06-07 03:30:11"},
{"id":5,"product_id":"3","name":"Package 3-1","jumlah_user":"12","created_at":"2017-06-07 03:31:36","updated_at":"2017-06-07 03:31:36"},
]]
List Price
[[
{"id":1,"package_id":"1","harga":"700000.00","masa_training":"2 x 1 jam","masa_maintenance":"2 bulan","tanggal_efektif":"2018-01-01","created_at":"2017-06-07 03:45:20","updated_at":"2017-06-07 03:45:20"},
{"id":2,"package_id":"2","harga":"500000.00","masa_training":"500","masa_maintenance":"100","tanggal_efektif":"2019-01-01","created_at":"2017-06-07 03:48:23","updated_at":"2017-06-07 03:48:23"},
{"id":3,"package_id":"3","harga":"50000.00","masa_training":"10","masa_maintenance":"20","tanggal_efektif":"2017-11-30","created_at":"2017-06-08 23:11:49","updated_at":"2017-06-08 23:11:49"}
]]
and this is how my menu will looks :
<ul class="list-group">
<li class="btn btn-lg btn-default list-group-item btn-menu">
<p class="productid" hidden>1</p>
<p class="productname">Product Name</p>
</li>
<li class="btn btn-lg btn-default list-group-item btn-menu">
<p class="productid" hidden>1</p>
<p class="productname">Product Name</p>
</li>
<li class="btn btn-lg btn-default list-group-item btn-menu">
<p class="productid" hidden>1</p>
<p class="productname">Product Name</p>
</li>
</ul>
```
and each button directly go to price list that connected to the product category.
Anyone have idea and can solved mine? thanks.
Assuming we have the json data stored in its corresponding variables, we could do like this:
(function() {
var productCategories = [
[{
"id": 1,
"name": "Product 1",
"created_at": "2017-06-06 08:31:34",
"updated_at": "2017-06-06 09:16:18"
},
{
"id": 2,
"name": "Product 2",
"created_at": "2017-06-06 09:16:12",
"updated_at": "2017-06-06 09:16:12"
},
{
"id": 3,
"name": "Product 3",
"created_at": "2017-06-06 09:16:24",
"updated_at": "2017-06-06 09:16:24"
}
]
];
var packageCategories = [
[{
"id": 1,
"product_id": "1",
"name": "Package 1-1",
"jumlah_user": "1",
"created_at": "2017-06-06 09:34:11",
"updated_at": "2017-06-06 09:34:11"
},
{
"id": 2,
"product_id": "1",
"name": "Package 1-2",
"jumlah_user": "1",
"created_at": "2017-06-06 09:35:49",
"updated_at": "2017-06-06 10:03:43"
},
{
"id": 3,
"product_id": "2",
"name": "Package 2-1",
"jumlah_user": "1",
"created_at": "2017-06-07 03:03:35",
"updated_at": "2017-06-07 03:03:35"
},
{
"id": 4,
"product_id": "2",
"name": "Package 2-2",
"jumlah_user": "1",
"created_at": "2017-06-07 03:30:11",
"updated_at": "2017-06-07 03:30:11"
},
{
"id": 5,
"product_id": "3",
"name": "Package 3-1",
"jumlah_user": "12",
"created_at": "2017-06-07 03:31:36",
"updated_at": "2017-06-07 03:31:36"
},
]
];
var listPrice = [
[{
"id": 1,
"package_id": "1",
"harga": "700000.00",
"masa_training": "2 x 1 jam",
"masa_maintenance": "2 bulan",
"tanggal_efektif": "2018-01-01",
"created_at": "2017-06-07 03:45:20",
"updated_at": "2017-06-07 03:45:20"
},
{
"id": 2,
"package_id": "2",
"harga": "500000.00",
"masa_training": "500",
"masa_maintenance": "100",
"tanggal_efektif": "2019-01-01",
"created_at": "2017-06-07 03:48:23",
"updated_at": "2017-06-07 03:48:23"
},
{
"id": 3,
"package_id": "3",
"harga": "50000.00",
"masa_training": "10",
"masa_maintenance": "20",
"tanggal_efektif": "2017-11-30",
"created_at": "2017-06-08 23:11:49",
"updated_at": "2017-06-08 23:11:49"
}
]
];
function buildProductCategoryMenu(productCategories) {
var ul = "",
i, obj, len = productCategories.length;
ul = "<ul class=\"list-group\">";
for (i = 0; i < len; i++) {
obj = productCategories[i];
ul += "<li class=\"btn btn-lg btn-default list-group-item btn-menu\">";
ul += "<p class=\"productid\" hidden>";
ul += obj.id;
ul += "</p>";
ul += "<p class=\"productname\">";
ul += obj.name;
ul += "</p>";
ul += "</li>";
}
ul += "</ul>";
return ul;
}
function setEventsProductCategoryMenu() {
var elems = document.getElementsByClassName("productname"),
i, len = elems.length,
ele;
for (i = 0; i < len; i++) {
ele = elems[i];
ele.onclick = function() {
showPackageName(this.previousSibling.innerHTML, packageCategories[0]);
};
}
}
function showPackageName(id, packageCategories) {
var packageCategory = packageCategories.find(function(x) {
return x.product_id === id;
});
if (packageCategory !== undefined) {
document.getElementById("packageName").innerHTML = "Package Name: " + packageCategory.name;
document.getElementById("price").innerHTML = "Price: " + showPriceBasedPackageCategory(packageCategory.id, listPrice[0]);
}
}
function showPriceBasedPackageCategory(id, listPrice) {
var obj;
obj = listPrice.find(function(x) {
return x.package_id === id.toString();
});
return (obj === undefined) ? "" : obj.harga;
}
document.getElementById("menu").innerHTML = buildProductCategoryMenu(productCategories[0]);
setEventsProductCategoryMenu();
})();
#menu {
border: solid 1px #ccc;
}
#content {
border: solid 1px #555;
}
<div id="menu"></div>
<div id="content">
<p id="packageName"></p>
<p id="price"></p>
</div>
With AJAX (Native JavaScript XMLHttpRequest() object):
By using a simple json file which contains all the data getting from the server.
JSON File: https://gist.githubusercontent.com/dannyjhonston/786a8e7c3f4ff1a0569013a1d4d1b8ad/raw/eb62b89d43e310997f9507be2d25f7fa375ddb6c/productCategoryPackageCategoryListPrice.json
(function() {
var newXHR = null;
// XMLHttpRequest helper function.
function sendXHR(type, url, data, callback) {
newXHR = new XMLHttpRequest() || new window.ActiveXObject("Microsoft.XMLHTTP");
newXHR.open(type, url, true);
newXHR.send(data);
newXHR.onreadystatechange = function() {
if (this.status === 200 && this.readyState === 4) {
callback(this.response);
}
};
}
function buildProductCategoryMenu(productCategories) {
var ul = "",
i, obj, len = productCategories.length;
ul = "<ul class=\"list-group\">";
for (i = 0; i < len; i++) {
obj = productCategories[i];
ul += "<li class=\"btn btn-lg btn-default list-group-item btn-menu\">";
ul += "<p class=\"productid\" hidden>";
ul += obj.id;
ul += "</p>";
ul += "<p class=\"productname\">";
ul += obj.name;
ul += "</p>";
ul += "</li>";
}
ul += "</ul>";
return ul;
}
function setEventsProductCategoryMenu(packageCategories, listPrice) {
var elems = document.getElementsByClassName("productname"),
i, len = elems.length,
ele;
for (i = 0; i < len; i++) {
ele = elems[i];
ele.onclick = function() {
showPackageName(this.previousSibling.innerHTML, packageCategories, listPrice);
};
}
}
function showPackageName(id, packageCategories, listPrice) {
var packageCategory = packageCategories.find(function(x) {
return x.product_id === id;
});
if (packageCategory !== undefined) {
document.getElementById("packageName").innerHTML = "Package Name: " + packageCategory.name;
document.getElementById("price").innerHTML = "Price: " + showPriceBasedPackageCategory(packageCategory.id, listPrice);
}
}
function showPriceBasedPackageCategory(id, listPrice) {
var obj;
obj = listPrice.find(function(x) {
return x.package_id === id.toString();
});
return (obj === undefined) ? "" : obj.harga;
}
sendXHR("GET", "https://gist.githubusercontent.com/dannyjhonston/786a8e7c3f4ff1a0569013a1d4d1b8ad/raw/eb62b89d43e310997f9507be2d25f7fa375ddb6c/productCategoryPackageCategoryListPrice.json", null, function(response) {
if (response !== null && response.length > 0) {
var jsonResponse = JSON.parse(response);
document.getElementById("menu").innerHTML = buildProductCategoryMenu(jsonResponse.data.productCategories[0]);
setEventsProductCategoryMenu(jsonResponse.data.packageCategories[0], jsonResponse.data.listPrice[0]);
}
});
})();
#menu {
border: solid 1px #ccc;
}
#content {
border: solid 1px #555;
}
<div id="menu"></div>
<div id="content">
<p id="packageName"></p>
<p id="price"></p>
</div>
By using three json files which contains its corresponding data getting from the server.
JSON Files:
Product Categories: https://gist.githubusercontent.com/dannyjhonston/3e2689ac7197d69a9624b32d5600e150/raw/18e36651acb9b9883732081a18c7deae7388eb0f/productCategories.json.
Package Categories: https://gist.githubusercontent.com/dannyjhonston/5d0caaffd3e22506fe1311eb4e31b7cc/raw/09a305b83cb725907d8ee9c24d487bdd85591b14/packageCategories.json.
List Price: https://gist.githubusercontent.com/dannyjhonston/cd73c2caf8d53ff1f453eafc14046357/raw/c943af91e7dd3e5e14e5763d8a2a14f649ddd810/listPrice.json.
(function() {
var newXHR = null;
// XMLHttpRequest helper function.
function sendXHR(type, url, data, callback) {
newXHR = new XMLHttpRequest() || new window.ActiveXObject("Microsoft.XMLHTTP");
newXHR.open(type, url, true);
newXHR.send(data);
newXHR.onreadystatechange = function() {
if (this.status === 200 && this.readyState === 4) {
callback(this.response);
}
};
}
function buildProductCategoryMenu(productCategories) {
var ul = "",
i, obj, len = productCategories.length;
ul = "<ul class=\"list-group\">";
for (i = 0; i < len; i++) {
obj = productCategories[i];
ul += "<li class=\"btn btn-lg btn-default list-group-item btn-menu\">";
ul += "<p class=\"productid\" hidden>";
ul += obj.id;
ul += "</p>";
ul += "<p class=\"productname\">";
ul += obj.name;
ul += "</p>";
ul += "</li>";
}
ul += "</ul>";
return ul;
}
function setEventsProductCategoryMenu(packageCategories, listPrice) {
var elems = document.getElementsByClassName("productname"),
i, len = elems.length,
ele;
for (i = 0; i < len; i++) {
ele = elems[i];
ele.onclick = function() {
showPackageName(this.previousSibling.innerHTML, packageCategories, listPrice);
};
}
}
function showPackageName(id, packageCategories, listPrice) {
var packageCategory = packageCategories.find(function(x) {
return x.product_id === id;
});
if (packageCategory !== undefined) {
document.getElementById("packageName").innerHTML = "Package Name: " + packageCategory.name;
document.getElementById("price").innerHTML = "Price: " + showPriceBasedPackageCategory(packageCategory.id, listPrice);
}
}
function showPriceBasedPackageCategory(id, listPrice) {
var obj;
obj = listPrice.find(function(x) {
return x.package_id === id.toString();
});
return (obj === undefined) ? "" : obj.harga;
}
sendXHR("GET", "https://gist.githubusercontent.com/dannyjhonston/3e2689ac7197d69a9624b32d5600e150/raw/18e36651acb9b9883732081a18c7deae7388eb0f/productCategories.json", null, function(response) {
if (response !== null && response.length > 0) {
var jsonResponse = JSON.parse(response);
document.getElementById("menu").innerHTML = buildProductCategoryMenu(jsonResponse.productCategories[0]);
sendXHR("GET", "https://gist.githubusercontent.com/dannyjhonston/5d0caaffd3e22506fe1311eb4e31b7cc/raw/09a305b83cb725907d8ee9c24d487bdd85591b14/packageCategories.json", null, function(response) {
if (response !== null && response.length > 0) {
jsonResponse = JSON.parse(response);
var packageCategories = jsonResponse.packageCategories;
sendXHR("GET", "https://gist.githubusercontent.com/dannyjhonston/cd73c2caf8d53ff1f453eafc14046357/raw/c943af91e7dd3e5e14e5763d8a2a14f649ddd810/listPrice.json", null, function(response) {
if (response !== null && response.length > 0) {
jsonResponse = JSON.parse(response);
var listPrice = jsonResponse.listPrice;
setEventsProductCategoryMenu(packageCategories[0], listPrice[0]);
}
});
}
});
}
});
})();
#menu {
border: solid 1px #ccc;
}
#content {
border: solid 1px #555;
}
<div id="menu"></div>
<div id="content">
<p id="packageName"></p>
<p id="price"></p>
</div>

Looping through JSON Data to Generate HTML

I have JSON data that looks like this:
data = {
"tennis": [{
"Description": "Insert description here.",
"Price": 379.99,
"ProductName": "Babolat Play Pure Drive",
}, {
"Description": "Insert description here.",
"Price": 199.99,
"ProductName": "Yonex AI 98 Tennis Racquet",
}],
"basketball": [{
"Description": "Insert description here.",
"Price": 64.99,
"ProductName": "Wilson NCAA Solution Official Game Basketball",
}, {
"Description": "Insert description here.",
"Price": 59.99,
"ProductName": "Spalding NBA NeverFlat Size 7 Composite Leather Basketball",
}]
}
I am using this data to generate HTML so it looks properly formatted and easily readable for the user. The way I am doing this is by creating a for loop to read through tennis and basketball categories. For example:
for (var i = 0; i < data.tennis.length; i++) {
tennisProducts.push(data.tennis[i]);
var tennisProductsTitle = tennisProducts[i].ProductName;
var tennisProductsDescription = tennisProducts[i].Description;
var tennisProductsPrice = tennisProducts[i].Price;
var badge = document.createElement('div');
badge.className = 'badge';
badge.innerHTML =
'<h1>' + tennisProductsTitle + '</h1>' +
'<h2>' + tennisProductsDescription + '</h1>' +
'<div class="options-only-phone">' +
'<a class="service-provider-call" href="#" target="_blank"> Buy for $' + tennisProductsPrice + '</a>';
document.getElementById('tennis-products-list').appendChild(badge);
}
How can I create one for loop that can read through both (or multiple) categories?
Here is my working example in this JSFiddle: https://jsfiddle.net/dsk1279b/1
Double loop, one to iterate the object properties, the next to iterate the array:
for (var key in data) {
for (var i = 0; i < data[key].length; i++) {
//HTML logic
}
}
Final code:
for (var key in data) {
for (var i = 0; i < data[key].length; i++) {
var title = data[key][i].ProductName;
var desc = data[key][i].Description;
var price = data[key][i].Price;
var badge = document.createElement('div');
badge.className = 'badge';
badge.innerHTML =
'<h1>' + title + '</h1>' +
'<h2>' + desc + '</h1>' +
'<div class="options-only-phone">' +
'<a class="service-provider-call" href="#" target="_blank"> Buy for $' + price + '</a>';
//I gave the div the same ID's as the keys in the object for ease
document.getElementById(key).appendChild(badge);
}
}
data = {
"tennis": [{
"Description": "Insert description here.",
"Price": 379.99,
"ProductName": "Babolat Play Pure Drive",
}, {
"Description": "Insert description here.",
"Price": 199.99,
"ProductName": "Yonex AI 98 Tennis Racquet",
}],
"basketball": [{
"Description": "Insert description here.",
"Price": 64.99,
"ProductName": "Wilson NCAA Solution Official Game Basketball",
}, {
"Description": "Insert description here.",
"Price": 59.99,
"ProductName": "Spalding NBA NeverFlat Size 7 Composite Leather Basketball",
}]
}
for (var key in data) {
for (var i = 0; i < data[key].length; i++) {
var title = data[key][i].ProductName;
var desc = data[key][i].Description;
var price = data[key][i].Price;
var badge = document.createElement('div');
badge.className = 'badge';
badge.innerHTML =
'<h1>' + title + '</h1>' +
'<h2>' + desc + '</h1>' +
'<div class="options-only-phone">' +
'<a class="service-provider-call" href="#" target="_blank"> Buy for $' + price + '</a>';
document.getElementById(key).appendChild(badge);
}
}
body {
font-family: Arial, sans-serif;
line-height: 125%;
}
h1 {
font-size: 0.875em;
padding: 0;
margin: 0;
}
h2,
a {
font-size: 0.750em;
padding: 0;
margin: 0;
font-weight: normal;
}
a:hover {
text-decoration: none;
}
.badge {
border-radius: 2px;
border: 1px solid rgba(0, 0, 0, 0.15);
padding: 12px;
margin: 12px 0;
}
.badge:hover {
border: 1px solid rgba(0, 0, 0, 0.3);
}
<div id="tennis">
</div>
<hr>
<div id="basketball">
</div>
tymeJV has a good approach, but this can be made even easier.
for(var product in data) {
// logic
}
If you look at your data, you have an object that we're already iterating over in key/value form.
Since you have arrays of items per key, you can use the Array.forEach() function.
for(var product in data) {
// current is the current object in the array
data[product].forEach(function(current){
//HTML logic
})
}
You change the place where you're appending the html template, so I would recommend updating your data object to be something like this:
data = {
"tennis": {
"products: [
{
"Description": "Insert description here.",
"Price": 379.99,
"ProductName": "Babolat Play Pure Drive"
},
{
"Description": "Insert description here.",
"Price": 199.99,
"ProductName": "Yonex AI 98 Tennis Racquet"
}
],
"templateTarget": '#tennis-products-list'
}
"basketball":
"products": [
{
"Description": "Insert description here.",
"Price": 64.99,
"ProductName": "Wilson NCAA Solution Official Game Basketball"
},
{
"Description": "Insert description here.",
"Price": 59.99,
"ProductName": "Spalding NBA NeverFlat Size 7 Composite Leather Basketball"
}
],
"templateTarget": '#basketball-products-list'
}
Something like that is going to allow you to do this:
for(var product in data) {
// current is the current object in the array
product.forEach(function(current){
var badge = document.createElement('div');
badge.className = 'badge';
badge.innerHTML =
'<h1>' + current.productName + '</h1>' +
'<h2>' + current.description + '</h1>' +
'<div class="options-only-phone">' +
'<a class="service-provider-call" href="#" target="_blank"> Buy for $' + current.price + '</a>';
document.getElementById(current.templateTarget).appendChild(badge);
})
}
This can be further optimized by having that giant html string hidden in a script tag with type="text/x-template" (since the browser ignores script types it doesn't understand) and grabbing it with the innerHTML function by referencing the id property on the script tag.
Hope that helps!
Flatten the data to a single array of values with category as a property:
var _data = Object.keys(data).reduce(
(m,c) => m.concat(data[c].map(
(i) => (i.category = c) && i))
, []);
console.log(_data);
Use flattened array for UI:
_data.forEach((d) => {
var badge = document.createElement('div');
badge.className = 'badge';
badge.innerHTML = [
'<h1>',
d.ProductName,
'</h1><h2>',
d.Description,
'</h1><div class="options-only-phone">',
'<a class="service-provider-call" href="#" target="_blank"> Buy for $',
d.Price,
'</a>'].join('');
document.getElementById(d.category + '-products-list').appendChild(badge);
})
'use strict';
var data = {
"tennis": [{
"Description": "Insert description here.",
"Price": 379.99,
"ProductName": "Babolat Play Pure Drive",
}, {
"Description": "Insert description here.",
"Price": 199.99,
"ProductName": "Yonex AI 98 Tennis Racquet",
}],
"basketball": [{
"Description": "Insert description here.",
"Price": 64.99,
"ProductName": "Wilson NCAA Solution Official Game Basketball",
}, {
"Description": "Insert description here.",
"Price": 59.99,
"ProductName": "Spalding NBA NeverFlat Size 7 Composite Leather Basketball",
}]
}
var _data = Object.keys(data).reduce((m,c) => m.concat(data[c].map((i) => (i.category = c) && i) ), []);
console.log(_data);
_data.forEach((d) => {
var badge = document.createElement('div');
badge.className = 'badge';
badge.innerHTML = [
'<h1>',
d.ProductName,
'</h1><h2>',
d.Description,
'</h1><div class="options-only-phone">',
'<a class="service-provider-call" href="#" target="_blank"> Buy for $',
d.Price,
'</a>'].join('');
document.getElementById(d.category + '-products-list').appendChild(badge);
})
body {
font-family: Arial, sans-serif;
line-height: 125%;
}
h1 {
font-size: 0.875em;
padding: 0; margin: 0;
}
h2, a {
font-size: 0.750em;
padding: 0; margin: 0;
font-weight: normal;
}
a:hover {
text-decoration: none;
}
.badge {
border-radius: 2px;
border: 1px solid rgba(0, 0, 0, 0.15);
padding: 12px;
margin: 12px 0;
}
.badge:hover {
border: 1px solid rgba(0, 0, 0, 0.3);
}
<div id="tennis-products-list">
</div>
<hr>
<div id="basketball-products-list">
</div>

Categories