I have gone through this solution Parsing JSON objects for HTML table . But in this solution Object keys are pre-defined when creating table. But I have some json data which can have random data.
Somtimes it can be :
var data = {
"C#": 2172738,
"CSS": 9390,
"HTML": 135085,
"Java": 337323
}
Or, Sometimes it can be:
var data = {
"Go": 2172738,
"Ruby": 9390,
"Dart": 135085
}
That means keys are not fixed. That data object can be dynamic. I want to convert the dynamic object to html table. Let's say, I have a table where thead is defined and tbody is empty:
<table id="_myTable">
<thead>
<th>Language</th>
<th>Line of Codes</th>
</thead>
<tbody>
</tbody>
</table>
How should I approach to insert that dynamic object data to tbody.
You can use for...in, Template literals and element.insertAdjacentHTML(position, text); to accomplish your task:
var data = {
"C#": 2172738,
"CSS": 9390,
"HTML": 135085,
"Java": 337323
}
for (key in data) {
var tr = `<tr><td>${key}</td><td>${data[key]}</td></tr>`;
document.querySelector('#_myTable tbody').insertAdjacentHTML('beforeend', tr);
}
<table id="_myTable">
<thead>
<th>Language</th>
<th>Line of Codes</th>
</thead>
<tbody>
</tbody>
</table>
You can use Object.keys(data) to get all of keys for "language" table data and Object.values(data) or Object.keys(data).map(key => data[key]) for "line of codes" table data.
Related
I am getting a little stuck with this one. I am trying to use javascript on my website to convert my API JSON data to a table. Without using an array in an array of data in JSON, it works fine which each item on a new line but soon as I use an nested array of data in there, it has all the data on one line, seperated by a comma. Thinking a for loop would work here but i'm not 100% sure if this is the best method.
I have tried multiple searches online and tested around myself but I can't seem to get it to work.
The following is simple version of the JSON data I am working with:
MACLIST = ["ABC","DEF"]
IPLIST = ["10.10.10.10","20.20.20.20"]
ZONELIST = ["Inside","Outside"]
var json = [{"MAC":MACLIST,"IP":IPLIST,"ZONE":ZONELIST},{"SOMETHING ELSE":"OK"}];
Script used:
$(document).ready(function () {
ko.applyBindings({
teams: json
});
});
HTML used:
<table>
<thead>
<tr>
<th>Device</th>
<th>IP</th>
<th>Zone</th>
</tr>
</thead>
<tbody data-bind="foreach: teams">
<tr>
<td data-bind="text: MAC"></td>
<td data-bind="text: IP"></td>
<td data-bind="text: ZONE"></td>
</tr>
</tbody>
</table>
Working JSON version (without nested array data) works:
var json = [{"MAC":"ABC","IP":"10.10.10.10","ZONE":"Inside"},{"MAC":"DEF","IP":"20.20.20.20","ZONE":"Outside}];
Any tips or advice would be greatly appreciated
Testing URL JSFiddle Link
You can map over each row to create a string of html for each row. Then inside each row, map over each column to create the string of html for each cell.
var json = [{
"MAC": "ABC",
"IP": "10.10.10.10",
"ZONE": "Inside"
}, {
"MAC": "DEF",
"IP": "20.20.20.20",
"ZONE": "Outside"
}];
const makeCell = (content) => {
return `<td>${content}</td>`
}
const makeRow = (content) => {
return `<tr>${content}</tr>`
}
const table = document.querySelector('.table')
const colHeaders = Object.keys(json[0]).map(key => makeCell(key)).join('')
const bodyRows = json.map(row => {
return makeRow(Object.keys(row).map(col => makeCell(row[col])).join(''))
}).join('')
document.querySelector('thead tr').innerHTML = colHeaders
document.querySelector('tbody').innerHTML = bodyRows
<table>
<thead>
<tr></tr>
</thead>
<tbody>
</tbody>
</table>
Hopefully this article will help you resolve the problem
https://www.geeksforgeeks.org/how-to-convert-json-data-to-a-html-table-using-javascript-jquery/
I am getting json.stringyfy data and want to append all json.stringyfy data to table,with each tr editable but I don't know that much part of jquery so unable to get any idea can anyone tell me what should do to achieve this?
Json data got in response
[{"id":"1","name":"abc"}, user id 1 data
{"id":"2","name":"def"}, user id 2 data
{"id":"3","name":"xyz"}, user id 3 data
{"id":"4","name":"aaa"}] user id 4 data
Ajax call with success function to handle stringyfy data
$.ajax({
url: "<?= base_url('Test_controller/show_user') ?>",
type: 'POST',
data: {
},
success: function (response) {
var myJSON = JSON.stringify(response);
// code Here to append data in table one by one with content editable tr
}
});
Html table
<table class="show_data">
<tr>
<th>User id</th>
<th>User name</th>
</tr>
</table>
Just take your data and append it to the table. Loop through each entry in your data and (if using jquery) do .append(). I just create a simple variable with your json but you can do this with your myJSON variable inside of the success function.
var data = [{"id":"1","name":"abc"},
{"id":"2","name":"def"},
{"id":"3","name":"xyz"},
{"id":"4","name":"aaa"}]
data.forEach(user => {
$('.show_data').append(`<tr><td>${user.id}</td><td>${user.name}</td></tr>`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="show_data">
<tr>
<th>User id</th>
<th>User name</th>
</tr>
</table>
Edit
You are getting that in error because you are using JSON.stringify which makes your json a string. You can't iterate on a string. Just use response instead of JSON.stringify(response);
You may use jQuery.each() and build elements on the fly:
var myJSON = [{"id": "1", "name": "abc"},
{"id": "2", "name": "def"},
{"id": "3", "name": "xyz"},
{"id": "4", "name": "aaa"}];
$.each(myJSON, function (idx, ele) {
$('.show_data tbody').append(
$('<tr/>') // create a TR
.append($('<td/>', {text: ele.id})) // append the first TD
.append($('<td/>', {text: ele.name})) // append the second TD
);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="show_data">
<thead>
<th>User id</th>
<th>User name</th>
</thead>
<tbody>
</tbody>
</table>
Here's an example of the table of data I'm scraping:
The elements in red are in the <th> tags while the elements in green are in a <td> tag, the <tr> tag can be displayed according to how they're grouped (i.e. '1' is in it's own <tr>; HTML snippet:
EDIT: I forgot to add the surrounding div
<div class="table-cont">
<table class="tg-1">
<thead>
<tr>
<th class="tg-phtq">ID</td>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-0pky">1</td>
<td class="tg-0pky">2</td>
<td class="tg-0pky">3</td>
</tr>
</tbody>
</table>
<table class="tg-2">
<thead>
<tr>
<th class="tg-phtq">Sample1</td>
<th class="tg-phtq">Sample2</td>
<...the rest of the table code matches the pattern...>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-0pky">Swimm</td>
<td class="tg-dvpl">1:30</td>
<...>
</tr>
</tbody>
<...the rest of the table code...>
</table>
</div>
As you can see, in the HTML they're actually two different tables while they're displayed in the above example as only one. I want to generate a JSON object where the keys and values include the data from the two tables as if they were one, and output a single JSON Object.
How I'm scraping it right now is a bit of modified javascript code I found on a tutorial:
EDIT: In the below, I've been trying to find a way to select all relevant <th> tags from both tables and insert them into the same array as the rest of the <th> tag array and do the same for <tr> in the table body; I'm fairly sure for the th I can just insert the element separately before the rest but only because there's a single one - I've been having problems figuring out how to do that for both arrays and make sure all the items in the two arrays map correctly to each other
EDIT 2: Possible solution? I tried using XPath Selectors and I can use them in devTools to select everything I want, but page.evaluate doesn't accept them and page.$x('XPath') returns JSHandle#node since I'm trying to make an array, but I don't know where to go from there
let scrapeMemberTable = async (page) => {
await page.evaluate(() => {
let ths = Array.from(document.querySelectorAll('div.table-cont > table.tg-2 > thead > tr > th'));
let trs = Array.from(document.querySelectorAll('div.table-cont > table.tg-2 > tbody > tr'));
// the above two lines of code are the main problem area- I haven't been
//able to select all the head/body elements I want in just those two lines of code
// just removig the table id "tg-2" seems to deselect the whole thing
const headers = ths.map(th => th.textContent);
let results = [];
trs.forEach(tr => {
let r = {};
let tds = Array.from(tr.querySelectorAll('td')).map(td => td.textContent);
headers.forEach((k,i) => r[k] = tds[i]);
results.push(r);
});
return results; //results is OBJ in JSON format
}
}
...
results = results.concat( //merge into one array OBJ
await scrapeMemberTable(page)
);
...
Intended Result:
[
{
"ID": "1", <-- this is the goal
"Sample1": "Swimm",
"Sample2": "1:30",
"Sample3": "2:05",
"Sample4": "1:15",
"Sample5": "1:41"
}
]
Actual Result:
[
{
"Sample1": "Swimm",
"Sample2": "1:30",
"Sample3": "2:05",
"Sample4": "1:15",
"Sample5": "1:41"
}
]
edit: updated this thread to clarify my question.
I make an ajax call that returns a dataset in json which looks like this:
Everything (including the correct column names) has already been taken care of via DB views so I wanted to write a script that just grabs a dataset and spits it out in a nicely formatted html table. This way the DB's table\view can be changed (columns added and removed) and the code will not have to be updated. I've been trying to get this to work with mustache but there doesn't seem to be a simple way of doing it. In the examples I find of people using mustache with an array of objects they are all explicitly referencing the objects properties in the template. I don't know the number or name of the objects' properties (the dataset's columns) will be a head of time so I can't enter them statically in the template.
Right now I'm using two templates, one for the headers and one just for the table rows:
<script id="datasetTable" type="text/template">
<table class="table table-hover table-bordered">
<thead>
<tr>
{{#headers}}
<th>{{.}}</th>
{{/headers}}
</tr>
</thead>
<tbody>
</tbody>
</table></script>
<script id="datasetTableRows" type="text/template">
<tr>
{{#rows}}
<td>{{.}}</td>
{{/rows}}
</tr>
</script>
And here is how I'm using it:
//Build table headers from dataset's columns
datasetCols = [];
for (var keyName in dataset[0]){
datasetCols.push(keyName);
};
//Build table rows from dataset rows
var renderedTableRows = '';
var tplRows = document.getElementById('datasetTableRows').innerHTML;
datasetLength = dataset.length;
for (var i=0; i<datasetLength; i++) {
var currentRow = dataset[i];
var rowValues = [];
for (var prop in currentRow){
rowValues.push(currentRow[prop]);
}
var renderedHtml = Mustache.render(tplRows, {rows: rowValues});
renderedTableRows += renderedHtml;
}
//render table with headers
var $renderedTable = $(Mustache.render('datasetTable', {headers: datasetCols}));
$renderedTable.find('tbody').html(renderedTableRows);
$(htmlContainer).html($renderedTable);
This works fine, but I really would like to simplify it further by using only one template. Can mustache process this in a more efficient way- without me having to explicitly reference the objects properties' names in the template?
I'd also like to add that I am already using mustache in a bunch of other places (code I don't feel like re-writing with a new engine right now) so if mustache can't do it I'll stick to pure js for the time being.
I've not personally used moustache, but they're all very similar.
Also, since it is logic-less you really want to return a more useful format. I.e an array of arrays would be better in this instance.
[["234", "ddg", "aa"], ["and, so on", "and so on", "and so on"]]
But if you know that there will always be three columns returned, you could do something like:
<table class="table table-hover table-bordered">
<thead>
<th> Whatever your headers are </th>
</thead>
<tbody>
{{#.}}
<tr>
<td>{{col1}}</td>
<td>{{col2}}</td>
<td>{{col3}}</td>
</tr>
{{/.}}
<tbody>
</table>
Or enumerate the object:
<table class="table table-hover table-bordered">
<thead>
<th> Whatever your headers are </th>
</thead>
<tbody>
{{#.}}
<tr>
{{#each dataSet}}
<td>{{this}}</td>
{{/each}}
</tr>
{{/.}}
<tbody>
</table>
Also, when creating HTML in javascript, use an array, it's faster.
var somehtml = [];
somehtml.push('something');
somehtml.push('something else');
somehtml = somehtml.join('');
I have an HTML table with combined row td's, or how to say, I don't know how to express myself (I am not so good at English), so I show it! This is my table:
<table border="1">
<thead>
<tr>
<th>line</th>
<th>value1</th>
<th>value2</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2">1</td>
<td>1.1</td>
<td>1.2</td>
</tr>
<tr>
<td>1.3</td>
<td>1.4</td>
</tr>
<tr>
<td rowspan="2">2</td>
<td>2.1</td>
<td>2.2</td>
</tr>
<tr>
<td>2.3</td>
<td>2.4</td>
</tr>
</tbody>
</table>
(you can check it here)
I want to convert this table to a JSON variable by jquery or javascript.
How should it look like, and how should I do it? Thank you, if you can help me!
if you want to convert only text use this one :
var array = [];
$('table').find('thead tr').each(function(){
$(this).children('th').each(function(){
array.push($(this).text());
})
}).end().find('tbody tr').each(function(){
$(this).children('td').each(function(){
array.push($(this).text());
})
})
var json = JSON.stringify(array);
To make a somehow representation of your table made no problem to me, but the problem is how to parse it back to HTML! Here a JSON with the first 6 tags:
{"table":{"border":1,"thead":{"th":{"textContent":"line","tr":"textContent":"value1",...}}}}}...
OR for better understanding:
{"tag":"table","border":1,"child":{"tag":"thead","child":{"tag":"th","textContent":"line",
"child":{"tag":"tr","textContent":"value1","child":...}}}}...
Closing tags are included.
For further explanations I need to know whether your table is a string or part of the DOM.
I belive this is what you want:
var jsonTable = {};
// add a new array property named: "columns"
$('table').find('thead tr').each(function() {
jsonTable.columns = $(this).find('th').text();
};
// now add a new array property which contains your rows: "rows"
$('table').find('tbody tr').each(function() {
var row = {};
// add data by colum names derived from "tbody"
for(var i = 0; i < jsonTable.columnsl.length; i++) {
row[ col ] = $(this).find('td').eq( i ).text();
}
// push it all to the results..
jsonTable.rows.push( row );
};
alert(JSON.stringify(jsonTable));
I think there should be some corrections, but this is it I think.