Build dynamic table from JSON - javascript

I've been stuck trying to build this dynamic table for the past couple of days. I've built it out several different ways and have finally gotten it to a point where I have the correct output, however the work I've done is manual. I am hoping someone could help me make this be more dynamic.
here's an example of my JSON (super simplified)
var obj1 = {
"Summary" :
[
{
"ID" : "1234",
"Name" : "John",
"Status" : "Green",
},
{
"ID" : "5678",
"Name" : "Mike",
"Status" : "Green",
},
{
"ID" : "9012",
"Name" : "Tom",
"Status" : "Red",
},
{
"ID" : "3456",
"Name" : "Chris",
"Status" : "Red",
},
{
"ID" : "2445",
"Name" : "Pat",
"Status" : "Green",
},
{
"ID" : "6543",
"Name" : "James",
"Status" : "Red",
}
]
};
I need the output to look something like this (which it is), however I may have more than 6 objects in my array, so I need to iterate through this rather than build it out by hand.
1234 5678 9012 3456 2445 6543
John Mike Tom Chris Pat James
Green Green Red Red Green Green
Here's my code thus far. Any help would be much appreciated.
for (j in obj1.Summary[0]) {
document.write('<tr><td class="' + j +'">' + j + '</td><td class="' + j +'">' + obj1.Summary[0][j] + '</td><td class="' + j +'">' + obj1.Summary[1][j] + '</td><td class="' + j +'">' + obj1.Summary[2][j] + '</td><td class="' + j +'">' + obj1.Summary[3][j] + '</td><td class="' + j +'">' + obj1.Summary[4][j] + '</td><td class="' + j +'">' + obj1.Summary[5][j] + '</td></tr>');
}

I recently came up with an interesting pattern for creating tables from database output dynamically, while holding references to the relevant created elements and the values used to create them.
This method came in handy for me because I created input elements for each table cell, then utilized the structure created to check the original values against their actual values and generate an sql update query based on the changed fields.
I realize that it may be overkill for this specific situation, but it does aid in readability and maintainability so I'm posting it here in case it could possibly help someone else in the future.
var responseText = {"Summary":[{"ID":"1234","Name":"John","Status":"Green",}, {"ID":"5678","Name":"Mike","Status":"Green",}, {"ID":"9012","Name":"Tom","Status":"Red",}, {"ID":"3456","Name":"Chris","Status":"Red",}, {"ID":"2445","Name":"Pat","Status":"Green",}, {"ID":"6543","Name":"James","Status":"Red",}]};
var list = new List(responseText.Summary);
document.body.appendChild(list.node);
function List(data) {
if(!(this instanceof List)) return false;
var list = this.node = document.createElement('div');
list.setAttribute('class','list');
var items = this.items = {};
for(var i in data) {
items[i] = new ListItem(data[i])
list.appendChild(items[i].node);
}
}
function ListItem(data) {
if(!(this instanceof ListItem)) return false;
var item = this.node = document.createElement('div');
item.setAttribute('class','item');
var lines = this.lines = {};
for(var i in data) {
lines[i] = new ListItemLine(i, data[i])
item.appendChild(lines[i].node);
}
}
function ListItemLine(name, value) {
if(!(this instanceof ListItemLine)) return false;
var line = this.node = document.createElement('div');
this.name = name;
this.value = value;
line.setAttribute('class','line ' + name);
if(name !== 'ID')
line.setAttribute('contenteditable', true);
line.appendChild(document.createTextNode(value));
}
.item {
display: inline-block;
padding: 5px;
text-align: center;
}
Then I used something similar to this inside the List class,
list.onkeydown = function(e) {
if(e.which !== 13) return true;
e.preventDefault();
var changes = [];
for(var i in items) (function(item, data){
for(var i in data.lines) (function(line){
var value = line.value,
actual = line.node.textContent;
if(value !== actual) changes.push({
id: data.lines['ID'].value,
name: line.name,
value: actual
});
})(data.lines[i]);
})(i, items[i]);
console.log(encodeURIComponent(JSON.stringify(changes)));
}
Where instead of using console.log, I send the data via ajax to a receiver page that generates update sql and returns the result of the query. Of course there are many methods of doing the last part of this, this is the one that was the most useful for me.

Make a variable and put the text in there. That way you can build it using nested loops then insert it in the document. I just did something similar in PHP that can take a db table as nested arrays and generate a table from it.
var table = "<table>";
//we loop over the attributes since you want that format
for (userAttribute in obj1.Summary[0]) {
//these are your headers/titles
table += '<tr><th>' + userAttribute + '</th>';
//and here we build a row getting the attribute from each user
for (userIndex in obj1.Summary) {
var user = obj1.Summary[userIndex];
table += '<td>' + user[userAttribute] + '</td>';
}
table += '</tr>'; //close that row and move on to the next attribute
}
//close out the table
table += '</table>';
document.write(table);

When you want to repeat logic, you should use a loop.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
for (var i=0; i < obj.Summary.length; i++) {
var object = obj.Summary[i]
// write to document
}
You should either transpose your data, or change your interface as well.
1234 John Green
5678 Mike Green
You may find a rendering library useful as well, to avoid messing with string concatenation.
https://github.com/leonidas/transparency
Edit
No problem, still use loops. Build the rows in the loop and concatenate them together. See the mdn array docs especially forEach and join.
// specify keys and init rows
var keys = [ "ID" ]
var rows = {}
keys.forEach(function (key) {
rows[key] = []
})
// ok now we have rows
console.log(rows)
// add table cells to rows
summaryObjects.forEach(function (object) {
for (var key in object) {
var cell = "<td>" + object[key] + "</td>"
rows[key].push(cell)
}
})
// now we have cells in the rows
console.log(rows)
// put together the table
keys.forEach(function (key) {
document.write("<tr>" + rows[key].join('') + "</tr>")
})
That's what i mean by transpose above, like a matrix transpose in linear algebra. Your data looks like this:
[
{ key: value, key: value }
{ key: value, key: value }
]
And you want
{
key: [ value, value ],
key: [ value, value ]
}

I would suggest using template such as Handlebarsjs to do this. This way, you keep the html separated from JavaScript and you don't have to add so many '+'.
For example, you can embed this on your html.
<script id="template" type="text/x-handlebars-template">
{{#each Summary}}
<tr><td>{{this.ID}}</td>
<td>{{this.Name}}</td>
<td>{{this.Status}}</td>
</tr>
{{/each}}
</script>
I think I messed up the tags but you get the idea.
Then on the script file, you can compile the template and get the data. More info on http://handlebarsjs.com/
var PROJECT_METHOD ={
handlerData:function(resJSON){
var templateSource = $("#template").html(),
template = Handlebars.compile(templateSource),
projectHTML = template(resJSON),
parser = new DOMParser(),
// the result
doc = parser.parseFromString(projectHTML, "text/html");
document.write(doc);
},
loadProjectData : function(){
$.ajax({
url:"data.json",
method:'get',
success:this.handlerData
});
}
};
PROJECT_METHOD.loadProjectData();
Hope it helps.

Related

Looping inside an object

I had encountered something unclear to me in the for loop:
var info = {
"full_name" : "John Doe",
"title" : "FrontEnd",
"links" : {
"blog" : "JohnDoe.com",
"facebook" : "http://facebook.com/JohnDoe",
"youtube" : "http://www.youtube.com/JohnDoe",
"twitter" : "http://twitter.com/JohnDoe"
}
};
I'm looping through this object with this loop:
var output = "";
for (var key in info.links ) {
if (info.links.hasOwnProperty(key)) {
output += '<li>' +
'<a href = "' + info.links[key] +
'">' + key + '</a>' +
'</li>';
console.log(key);
}
}
var update = document.getElementById('links');
update.innerHTML = output;
And my question is, what is var key in this loop and why it works when there is no var key in scope of this loop? In this case var key becomes blog, facebook etc. inside info.links object. But why?
Go thorough this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
for (variable in object) { ...
}
Variable "A different property name is assigned to variable on each iteration."
In your case "facebook", "twitter" , etc are your property names in object
var means that you're declaring a new variable, key is the name you give this variable.
Since you're looping through everthing in info.links you want to be able to call each var individually
Look this for a sample solution. The key represents the keys of the info.links object say blog, facebook etc, thus info.links[key] represents the value i.e,
info.links["blog"] = "JohnDoe.com",
info.links["facebook"] = "http://facebook.com/JohnDoe"
Hope this is clear.
Look this link for loop description

searching deeper than 1 into json

im trying to figure out how to search deeper than just one deep in my JSON file.
its structure is as follows
json>data>movies>
in movies the different movies are enumerated 0, 1, 2, 3, 4, etc so
json>data>movies>3>
would contain movie information for the 4th movie
each containing key value pairs.the code i am using only seems to look one deep, and i cant seem to get it to go deeper.
code is as follows
$('#search').keyup(function () { // i understand this to watch the form id search
var searchField = $('#search').val(); // sets variable searchfield from typed content, .val grabs the content
if (searchField.length) // this sets the length to false by default ensuring the code only runs when it is supposed to and not all the time
{
var myExp = new RegExp(searchField, "i"); // sets variable myexp to regular expression using "i" for case insensitive
var found = 0; // sets variable found to 0 to keep div hidden until match is found
$.getJSON('/secure/movies.json', function (data) { //gets movies.json file pushes to data function
var output = '<ul class="searchresults">';
$.each(data, function (key, val) { // this should make key pairs from data
if (val.title.search(myExp) !== -1) { // this is the problem i think
console.log(val); // this should show our search term results in console
found = 1;
output += '<li>';
output += '<h2>' + val.title + '</h2>';
output += "<a href=" + val.image + ' target="_blank" ></a>';
output += '</li>';
}
});
output += '</ul>';
if (found == 1) {
$('#update').removeClass('update-hidden');
$('#update').html(output);
} else {
$('#update').addClass('update-hidden');
}
});
} else {
$('#update').addClass('update-hidden');
}
});
ive tried manipulating val.title.search(myexp) but i might be missing the boat on whats happening here with val.title.search. thanks in advance

How do I extract JSON string using a JavaScript variable?

I am currently trying to retrieve the corresponding dial_code by using the name which I am obtaining as a variable.
The application uses a map of the world. When the user hovers over a particular country, that country is obtained using 'getRegionName'. This is then used to alter the variable name. How can I use the variable name to retrieve the dial_code that it relates to?
JSON
var dialCodes = [
{"name":"China","dial_code":"+86","code":"CN"},
{"name":"Afghanistan","dial_code":"+93","code":"AF"}
];
The following code runs on mouse hover of a country
var countryName = map.getRegionName(code);
label.html(name + ' (' + code.toString() + ')<br>' + dialCodes[0][countryName].dial_code);
This code doesn't work correctly. The dialCodes[0][countryName].dial_code is the part that is causing the error, but I'm not sure how to correctly refer to the corresponding key/value pair
If you have to support old browsers:
Loop over the entries in the array and compare to the given name:
var dialCode;
for(var i = 0; i < dialCodes.length; i++) {
if(dialCodes[i].name === countryName) {
dialCode = dialCodes[i].dial_code;
break;
}
}
label.html(countryName + ' (' + dialCode + ')');
If you browser support Array.prototype.filter:
dialCodes.filter(function(e) { return e.name === 'China' })[0].dial_code
If you have control over it, I recommend making your object more like a dictionary, for example if you are always looking up by the code (CN or AF) you could avoid looping if you did this:
var dialCodes = {
CN: { "name":"China","dial_code":"+86","code":"CN" },
AF: {"name":"Afghanistan","dial_code":"+93","code":"AF"}
};
var code = dialCodes.CN.dial_code;
Or
var myCode = 'CN'; // for example
var code = dialCodes[myCode].dial_code;
Since it's an array you can use filter to extract the data you need.
function getData(type, val) {
return dialCodes.filter(function (el) {
return el[type] === val;
})[0];
}
getData('code', 'CN').dial_code; // +86

Named Array Keys using .map() and .get()

I need to output inputs and their values into a div. However, because I need to match the correct labels to the correct inputs, and some fields allow null values, I'm running into matching issues. Using the following code to pull each label/input into an array, and then output:
var inputArr = $('input, select').map(function(){
return "<p>" + $(this).val() + "</p>";
}).get()
var labelArr = $('label').map(function(){
return "<p>" + $(this).text() + "</p>";
}).get()
function setValuesForConfirm() {
//Clear Div Contents
$("#test-output-1, #test-output").html('');
for (var i = 0; i < labelArr.length; i++) {
$("#test-output-1").append(labelArr[i]);
}
for (var i = 0; i < inputArr.length; i++) {
$("#test-output").append(inputArr[i]);
}
}
So if any of the input's are blank, the fields do not match the labels.
My question is, can I name the array keys to the field name or ID in JS using the .map() function as I am currently?
JSFiddle Here
You could create an object using the inputs:
var formObj={};
$('input, select').each(function(){
formObj[this.name]={val: this.value, labelText: $(this).prev('label').text()};
});
then when loop over object can throw together html
$.each(formObj, function(key, item){
var labelHtml='<p>'+item.labelText+'</p>';
var inputHtml='<p>Name: '+ key+', value: '+item.val+'</p>';
/* do something with html*/
})
While what you have seems to work okay to me, .map creates an array and you can only have numeric ordinal keys in arrays in JavaScript, so you would need an object.
var inputArr = {};
$('input, select').each(function(){
inputArr[$(this).attr('name')] = "<p>" + $(this).val() + "</p>";
});
http://jsfiddle.net/Mz9Vy/1/

how to get random json data and append to div element

Say this is my json
[
{
"imageSmall": ["images/employee_jpgs/employees_abhishek_80x80.jpg"],
"imageBig": ["images/employee_jpgs/employees_abhishek_150x150.jpg"],
"name": ["Abhishek Shet"],
"quotes": ["Just perfect to start your career after school. Makes me feel others in the industry are way slower then us. Awesome team and and a brilliant product to work on!!!!. And most importantly I enjoy what I do :)."],
"type": "employee"
},
{
"imageSmall": ["images/employee_jpgs/employees_barbra_80x80.jpg"],
"imageBig": ["images/employee_jpgs/employees_barbra_150x150.jpg"],
"name": ["Barbra Gago"],
"quotes": ["The best part about working at tibbr is how dynamic the environment is, there's a lot of flexibility and freedom to execute on new ideas. Because everyone is so talented, there is a ton of trust and support coming from managers and team members-we all count on each other to do the best possible job!"],
"type": "employee"
},
the same continues but there are 3 types
1-employee
2-twitter
3-social
Now my problem is I want get these json data randomly and append to my div element
I used following code
function(args){
var me=this;
$.getJSON(args.json,function(data) {
me.set(args);
$.each(data, function(i){
var id="randomizr_item_" + i;
var temp= $('<div id='+ id +' class="randomizr-grid-items"><img src="'+ this.imageSmall[0] +'" /></div>');
me.config.container.append(temp);
this.target=$(temp);
});
I know how to generate single random entry using following code
entry = data[Math.floor(Math.random()*data.length)];
which generates single random entry.
Plz help me how to get json data randomly from above json file and append to div.
You need to make an array of random unique numbers like following:
function generateRandom(min, max) {
var arr = [];
while(arr.length < 5){
var randNum = Math.floor(Math.random() * (max - min + 1)) + min,
found=false;
for(var i=0;i < arr.length; i++){
if(arr[i] == randNum){found=true;break}
}
if(!found)arr[arr.length] = randNum;
}
return arr;
}
Then you need to loop over data like following:
Here I am looping over unique array, not on data and using value of array as index to data.
var orders = generateRandom(0, data.length-1);
$.each(orders, function(index, value){
var id="randomizr_item_" + i;
var temp= $('<div id='+ id +' class="randomizr-grid-items"><img src="'+ data[value].imageSmall[0] +'" /></div>');
me.config.container.append(temp);
this.target=$(temp);
});
A simple demo
You should create a 'Deck' and fill it with the json data.
Once the Deck is filled, loop through it while it has elements, like this:
while(deck.length > 0) {
var random_index = Math.floor(Math.random()*data.length);
var item = deck[random_index];
// do stuff with item
deck = jQuery.removeFromArray(random_index, deck);
}
Add this code to the top of your js file:
jQuery.removeFromArray = function(value, arr) {
return jQuery.grep(arr, function(elem, index) {
return elem !== value;
});
};

Categories