I need to get data from a table and store it in an array. Each row of the table should be a new array within an array. Basically the html looks like this:
<table id="contactlisttable">
<tr>
<th>Name</th>
<th>Title</th>
<th>Phone</th>
</tr>
<tr>
<td class="contactlist contactlistlastfirst">Joey</td>
<td class="contactlist contactlisttitle">webdesigner</td>
<td class="contactlist contactlistphone">5555555</td>
</tr>
<tr>
<td class="contactlist contactlistlastfirst">Anthony</td>
<td class="contactlist contactlisttitle">webdesigner</td>
<td class="contactlist contactlistphone">5555555</td>
</tr>
</table>
ect...
Here is my code
jQuery(document).ready(function(){
$(function(){
var $table = $("#contactlisttable"),
$headerCells = $table.find("tr th"),
$myrows = $table.find("tr"); // Changed this to loop through rows
var headers = [],
rows = [];
$headerCells.each(function() {
headers[headers.length] = $(this).text();
});
$myrows.each(function() {
$mycells = $myrows.find( "td.contactlist" ); // loop through cells of each row
cells = []
$mycells.each(function() {
cells.push($(this).text());
});
if ( cells.length > 0 ) {
rows.push(cells);
}
});
console.log(headers);
console.log(rows);
});
});
my current code out puts
[["Waddell, Joey", "webdesigner", "", 15 more...], ["Waddell, Joey", "webdesigner", "", 15 more...],
the desired output would be:
["Name","Title","Phone"]
[["Joey","webdesigner","555555"]
["Anthony","webdesigner","555555"]]
I think this can be simpler:
Live Demo
JS
$(function(){
var results = [];
var row = -1;
$('#contactlisttable').find('th, td').each(function(i, val){
if(i % 3 === 0){ //New Row?
results.push([]);
row++;//Increment the row counter
}
results[row].push(this.textContent || this.innerText); //Add the values (textContent is standard while innerText is not)
});
console.log(results);
});
EDIT
Here's an even better solution (IE9+ compatible). It accounts for variable row lengths unlike my previous solution.
Live Demo
JS
//IE9+ compatable solution
$(function(){
var results = [], row;
$('#contactlisttable').find('th, td').each(function(){
if(!this.previousElementSibling){ //New Row?
row = [];
results.push(row);
}
row.push(this.textContent || this.innerText); //Add the values (textContent is standard while innerText is not)
});
console.log(results);
});
Related
Active learner here, trying to figure out how to create a JSON object out of HTML table. I only want the value of one specific TD and want to give each value an incrementing number as a key. I'd like an output like below. My table has a TD for the city names, but it does not have one with a incrementing numerical value so I'd need to add that another way.
{
"mycities" : [
{
"Seattle" : "1",
"Chicago" : "2",
"New York" : "3"
"Pitt" : "4",
"LA" : "5",
"Fresno" : "6"
},
]
}
Here is what my table looks like:
<table>
<thead>
<tr>
<th>city name</th>
<th>other city info</th>
</tr>
</thead>
<tbody>
<tr>
<td>Seattle</td>
<td>Lots of rain</td>
</tr>
etc,etc,etc
</tbody>
</table>
I've tried using a replacer function but haven't got it figured out after much googling. Any help is appreciated!
$(document).ready(function(){
$("body").on("click",".submitButtonPri",function(){
count= 1;
function replacer(key, value) {
if (typeof value === 'string') {
return count;
}
return value;
}
var myRows = [];
var $headers = $(".rightDash > table thead th");
var $rows = $(".rightDash > table tbody tr").each(function(index) {
$cells = $(this).find("td.titlePri");
myRows[index] = {};
$cells.each(function(cellIndex) {
myRows[index][$($cells[cellIndex]).text()] = $(this).text();
});
count++;
});
var myObj = {};
myObj.myrows = myRows;
console.log(JSON.stringify(myObj,replacer));
});
});
Use reduce to iterate over the trs in the body, using the text content of the first td in the tr as the city name. The third argument to the function provided to reduce represents the iteration index:
const cityData = [...document.querySelectorAll('tbody > tr')]
.reduce((a, tr, i) => {
a[tr.children[0].textContent] = i + 1;
return a;
}, {});
console.log(
{ mycities: [
cityData
]}
);
<table>
<thead>
<tr>
<th>city name</th>
<th>other city info</th>
</tr>
</thead>
<tbody>
<tr>
<td>Seattle</td>
<td>Lots of rain</td>
</tr>
<tr>
<td>Chicago</td>
<td>Lots of rain</td>
</tr>
<tr>
<td>New York</td>
<td>Lots of rain</td>
</tr>
</tbody>
</table>
You can start with this simple script:
$('td').each(function(index, obj) {console.log(index, $(this).html())});
It returns all what you need and you just need assemble JSON by any way
I have the following HTML table:
<table id="review-total">
<tbody><tr class="wlp">
<td class="left-cell">WLP Total</td>
<td>199.00</td>
</tr>
<tr class="tax">
<td class="left-cell">GST</td>
<td>19.90</td>
</tr>
<tr class="net">
<td class="left-cell">Order Total</td>
<td class="net-price">$218.90</td>
</tr>
</tbody>
</table>
I'm trying to loop through this table and retrieve the values i.e
199.00, 19.90 and $218.90 I have the following code:
var reviewTotal = document.getElementById('review-total');
for (var i = 1; i < reviewTotal.rows.length; i++) {
if (reviewTotal.rows[i].cells.length) {
wlpTotal = (reviewTotal.rows[i].cells[1].textContent.trim());
gstAmount = (reviewTotal.rows[i].cells[3].textContent.trim());
totalOrderAmount = (reviewTotal.rows[i].cells[5].textContent.trim());
}
}
I'm having a small issue trying to retrieve those values specified above, at present the error I get is textContent is undefined.
Can someone show me how I should go about retrieving those values, unfortunately I'm not strong in Javascript.
You have 3 rows and each row has only 2 cells. The 3 and 5 indices are undefined and undefined doesn't have .textContent property.
If you want to store the values by using specific variable names, you remove the loop and select the target elements manually:
var wlpTotal = reviewTotal.rows[0].cells[1].textContent.trim();
var gstAmount = reviewTotal.rows[1].cells[1].textContent.trim();
var totalOrderAmount = reviewTotal.rows[2].cells[1].textContent.trim();
If you want to store the values in an array, you can code:
var values = [].map.call(reviewTotal.rows, function(row) {
return row.cells[1].textContent.trim();
});
By using ES2015's Destructuring Assignment you can also extract the array's elements:
var [wlpTotal, gstAmount, totalOrderAmount] = values;
First:the index start the 0 either row or cell.
Secend:get value in the tag to use innerText or innerHTML ,The code following:
var reviewTotal = document.getElementById('review-total');
for (var i = 0; i < reviewTotal.rows.length; i++)
{
if (reviewTotal.rows[i].cells.length>1)
{
wlpTotal = (reviewTotal.rows[i].cells[1].innerText);
}
}
I'm working on a small userscript to sort a table, the structure of the table is really weird however. What i'm trying to do is to add an extra sort feature so I can sort on the ranking (#) of the persons.
Table data looks like this:
<table id="outer">
<tr>
<td><div id="bgn"></div></td>
<td>User 1</td>
<td>
<table id="inner">
<tbody>
<tr>
<td>Rank</td>
<td id="tdp">#28</td>
</tr>
</tbody>
</table>
</td>
</tr>
<!-- more rows -->
</table>
There are some additional <td>'s but they are not important right now. There are about 52 rows, but these could vary, of course.
Current jQuery code I have:
jQuery( document ).ready(function() {
var rankings = [];
$(document).on('click', '#tdr', function() {
// skipping first line because it's the header
$('tr:not(:first-child').each(function () {
var rank = $(this).find('#tdp').text();
var rank2 = rank.substring(1, rank.length)
rankings.push(rank2);
});
console.log(rankings.sort(sortNumber));
});
function sortNumber(num1, num2) {
return num1 - num2;
}
});
JS Bin Example
The output in the console is a correctly sorted array with all the rankings, I just don't have any idea how to also swap the corresponding <tr>'s so that the table get's rebuild the right way. Looking for any tips or pointers!
This suggestion is not really into "sorting" the rows, but re-constructing the table with the sorted rows. But this should do the job:
rankings = rankings.sort(sortNumber);
var table = $('<table></table>');
for (var i = 0; i < rankings.length; i++) {
var row = $('tr').filter(function() {
var rank = $(this).find('#tdp').text();
return rank.substring(1, rank.length) == i;
});
table.append(row);
}
$('#originalTable').html(table.html());
I'm using Josh Fraser's Backwards compatible window.postMessage() (http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage) and I'm having trouble.
I have 2 iframes on a page and both iframes send different data to the same parent page. In other words, there are 2 XD.receivemessage functions getting 2 different messages from 2 different iframes. Here's a shortened version of my code:
<iframe id="IFRAME1" src="https://www.DOMAIN.com/PAGENAMEFIRST.php"></iframe>
<iframe id="IFRAME2" src="https://www.DOMAIN.com/PAGENAMESECOND.php"></iframe>
<div id="firstTable">
<table>
<tr>
<th>Name</th>
<th>Address</th>
<th>ID</th>
</tr>
<tr>
<td><!--this will be filled in by the data--></td>
<td><!--this will be filled in by the data--></td>
<td><!--this will be filled in by the data--></td>
</tr>
</table>
</div>
<div id="secondTable">
<table>
<tr>
<th>Email</th>
<th>Twitter Handle</th>
<th>ID</th>
</tr>
<tr>
<td><!--this will be filled in by the data--></td>
<td><!--this will be filled in by the data--></td>
<td><!--this will be filled in by the data--></td>
</tr>
</table>
</div>
<script type="text/javascript">
$(document).ready(function() {
//FIRST DATA PULL
var encodeUriFirst = encodeURIComponent(document.location.href);
var getMessageFirst = 'https://www.DOMAIN.com/PAGENAMEFIRST.php#' + encodeUriFirst;
$("#IFRAME1").attr('src',getMessageFirst);
XD.receiveMessage(function(getMessageFirst){
var getDataFirst = getMessageFirst.data;
var getDataFirstEach = new Array();
for(var a=0; a<getDataFirst.length; a++){
getDataFirstEach = getDataFirst.split("~,~");
$('div#firstTable table td:nth-child(0)').text(getDataFirstEach[0].replace(/[~]/g,""));
}
}, 'https://www.DOMAIN.com');
//SECOND DATA PULL
var encodeUriSecond = encodeURIComponent(document.location.href);
var getMessageSecond = '//www.DOMAIN.com/PAGENAMESECOND.php#' + encodeUriSecond;
$("#IFRAME2").attr('src',getMessageSecond);
XD.receiveMessage(function(getMessageSecond){
var getDataSecond = getMessageSecond.data;
var getDataSecondEach = new Array();
for(var a=0; a<getDataFirst.length; a++){
getDataSecondEach = getDataSecond.split("~,~");
$('div#secondTable table td:nth-child(0)').text(getDataSecondEach[0].replace(/[~]/g,""));
}
}, 'https://www.DOMAIN.com');
});
</script>
Please keep in mind that I've scaled back the code significantly. Each getDataFirst or getDataSecond
It actually works as far as getting the data from both iframes (send/receive both work). My data comes through in the format ~name~,~address~,~ID~ for the first set of data and ~email~,~twitter~,~ID~ for the second set.
I'm trying to get the data to populate the 2 tables. The For loops look for the ID in the table and if the ID matches, it fills in the other fields associated with that ID. In some cases, the ID from the first data set will be the same as the ID from the second data set. When that happens, the for loops place the data in both tables instead of the appropriate one. I'm wondering why this would happen since I'm specifically targeting the table inside either $('div#firstTable') or $('div#secondTable') for the output. For example:
$('div#firstTable table td:nth-child(0)').text(getDataFirstEach[0]);
inside the For loop is placing getDataFirstEach[0] into both the firstTable and secondTable tables?
Can anyone tell me why?
AS REQUESTED, HERE IS THE FULL JS:
var encodeUriGifts = encodeURIComponent(document.location.href);
var giftsMessage = '//www.DOMAIN.org/firstpage.php#' + encodeUriGifts;
$("#IFRAME1").attr('src',giftsMessage);
XD.receiveMessage(function(giftsMessage){
var getDataGifts = giftsMessage.data;
var currentRecordGifts = new Array();
var getGiftsLines = getDataGifts.split("|"); //LINES OF DATA ARE PIPE SEPARATED
for(var bCnt=0;bCnt < getGiftsLines.length;bCnt++){
var getGiftsEach = getGiftsLines[bCnt].split("`,`"); //EACH ITEM IS SEPARATED BY `,`
for(var cCnt=0;cCnt < getGiftsEach.length;cCnt++){
if (getGiftsEach[cCnt]!=="" && getGiftsEach[cCnt]!=="undefined"){
currentRecordGifts[bCnt] = " <td class='giftamount'>"+getGiftsEach[1]+"</td><td class='giftdate'>"+getGiftsEach[2].replace(/[`]/g,"")+"</td>";
}
if (cCnt==2) {
var thisGiftsID = getGiftsEach[0].replace(/[`]/g,"");
$('#firstTable table td:contains("'+thisGiftsID+'")').closest('tr').find('td:nth-child(3)').after(currentRecordGifts[bCnt]);
}
}
if (bCnt==0){
$('#firstTable table th:nth-child(3)').after('<th class="BBListingHeading DirectoryListingHeading" scope="col" style="white-space: nowrap;">Last Gift Amount</th><th class="BBListingHeading DirectoryListingHeading" scope="col" style="white-space: nowrap;">Last Gift Date</th>');
}
}
}, 'https://www.DOMAIN.org');
var encodeUriChanges = encodeURIComponent(document.location.href);
var changesMessage = '//www.DOMAIN.org/secondpage.php#' + encodeUriChanges;
$("#IFRAME2").attr('src',changesMessage);
XD.receiveMessage(function(changesMessage){
var getDataChanges = changesMessage.data;
var currentRecordChanges = new Array();
var getChangesLines = getDataChanges.split("|");
$('#secondTable table tr td:nth-child(3)').each( function() {
$('#secondTable table tr td:nth-child(3)').after('<td class="BBListingItem DirectoryListingItem" style="white-space: nowrap;"><ul class="changes"></ul></td>');
});
for(var dCnt=0;dCnt < getChangesLines.length;dCnt++){
var getChangesEach = getChangesLines[dCnt].split("`,`");
for(var eCnt=0;eCnt < getChangesEach.length;eCnt++){
if (getChangesEach[eCnt]!=="" && getChangesEach[eCnt]!=="undefined"){
currentRecordChanges[dCnt] = "<li class='change'>"+getChangesEach[2]+" ("+getChangesEach[1].replace(/[`]/g,"")+")</li>";
}
if (eCnt==2) {
var thisChangesID = getChangesEach[0].replace(/[`]/g,"");
$('#secondTable table td:contains("'+thisChangesID+'")').closest('tr').find('td ul.changes').append(currentRecordChanges[dCnt]);
}
if (dCnt==0){
$('#changesdiv .DirectoryListingTable th:nth-child(3)').after('<th class="BBListingHeading DirectoryListingHeading" scope="col" style="white-space: nowrap;">Change Details</th>');
}
}
}
}, 'https://www.DOMAIN.org');
I am trying to sort a table - so when a user clicks on the table heading, it will sort in ascending/descending order. I've got it to the point where I can sort the table based on the column value. However, I have groupings of table rows (two rows per table body), and I want to sort the columns based on the values in the columns of the first row of each table body, but when it reorders the table, it want it to reorder the table bodies, not the table rows.
<table width="100%" id="my-tasks" class="gen-table">
<thead>
<tr>
<th class="sortable"><p>Name</p></th>
<th class="sortable"><p>Project</p></th>
<th class="sortable"><p>Priority</p></th>
<th class="sortable"><p>%</p></th>
</tr>
</thead>
<tbody>
<tr class="sortable-row" id="44">
<td><p>dfgdf</p></td><td><p>Test</p></td>
<td><p>1</p></td><td><p>0</p></td>
</tr>
<tr>
<td></td>
<td colspan="3"><p>asdfds</p></td>
</tr>
</tbody>
<tbody>
<tr class="sortable-row" id="43">
<td><p>a</p></td>
<td><p>Test</p></td>
<td><p>1</p></td>
<td><p>11</p></td>
</tr>
<tr>
<td></td>
<td colspan="3"><p>asdf</p></td>
</tr>
</tbody>
<tbody>
<tr class="sortable-row" id="40">
<td><p>Filter Tasks</p></td>
<td><p>Propel</p></td>
<td><p>10</p></td>
<td><p>10</p></td>
</tr>
<tr>
<td></td>
<td colspan="3"><p>Add a button to filter tasks.</p></td>
</tr>
</tbody>
</table>
With the following javascript:
jQuery(document).ready(function () {
jQuery('thead th').each(function(column) {
jQuery(this).addClass('sortable').click(function() {
var findSortKey = function($cell) {
return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
};
var sortDirection = jQuery(this).is('.sorted-asc') ? -1 : 1;
var $rows = jQuery(this).parent().parent().parent().find('.sortable-row').get();
jQuery.each($rows, function(index, row) {
row.sortKey = findSortKey(jQuery(row).children('td').eq(column));
});
$rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) return -sortDirection;
if (a.sortKey > b.sortKey) return sortDirection;
return 0;
});
jQuery.each($rows, function(index, row) {
jQuery('#propel-my-tasks').append(row);
row.sortKey = null;
});
jQuery('th').removeClass('sorted-asc sorted-desc');
var $sortHead = jQuery('th').filter(':nth-child(' + (column + 1) + ')');
sortDirection == 1 ? $sortHead.addClass('sorted-asc') : $sortHead.addClass('sorted-desc');
jQuery('td').removeClass('sorted').filter(':nth-child(' + (column + 1) + ')').addClass('sorted');
});
});
});
You need to sort the tbody elements, not the row elements. You said that yourself in your description of the problem, but your code actually sorts rows, not tbodies.
A secondary problem is that your sort treats everything as a string, which breaks when sorting 1-digit numeric strings ("2") against two-digit strings ("10").
To fix, replace this:
var $rows = jQuery(this).parent().parent().parent()
.find('.sortable-row').get();
jQuery.each($rows, function(index, row) {
row.sortKey = findSortKey(jQuery(row).children('td').eq(column));
});
with this:
var $tbodies = jQuery(this).parent().parent().parent()
.find('.sortable-row').parent().get();
jQuery.each($tbodies, function(index, tbody) {
var x = findSortKey(jQuery(tbody).find('tr > td').eq(column));
var z = ~~(x); // if integer, z == x
tbody.sortKey = (z == x) ? z : x;
});
And then replace $rows with $tbodies throughout your script, and row with tbody.
Example:
http://jsbin.com/oxuva5
I highly recommend the jQuery plugin http://tablesorter.com/ instead of rolling your own.
It's fully featured and well supported.