Retrieve html table contents of TD anchor with Javascript - javascript

I can not understand how to grab for example href attribute inside table row cell. When I'm trying to do that it seems that second loop does not work for selected TR elements
function asd(){
this.container = document.getElementsByClassName("cart-contents")[0];
if (!this.container){
return false;
}
this.itemsContainer =
this.container.getElementsByClassName("minicart-table")[0];
this.itemsTable = this.itemsContainer.getElementsByClassName("views-table")[0];
this.cartDetails = [];
for (var i = 0, row; row = this.itemsTable.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
console.log(col[0].getElementsByTagName("a")[0].getAttribute("href"));
}
console.log('________________');
}
}
asd();
<div class="cart-contents">
<div class="minicart-table">
<table class="views-table">
<tbody>
<tr>
<td class="views-field-field-product-image">text</td>
<td class="tg-yw4l"></td>
</tr>
</tbody>
</table>
</div>
</div>

Use col instead col[0]
function asd(){
this.container = document.getElementsByClassName("cart-contents")[0];
if (!this.container){
return false;
}
this.itemsContainer =
this.container.getElementsByClassName("minicart-table")[0];
this.itemsTable = this.itemsContainer.getElementsByClassName("views-table")[0];
this.cartDetails = [];
for (var i = 0, row; row = this.itemsTable.rows[i]; i++) {
// only the first column
col = row.cells[0];
var anchor = col.getElementsByTagName("a")[0];
if (anchor !== undefined) {
console.log(anchor.getAttribute("href"));
}
console.log('________________');
}
}
asd();
<div class="cart-contents">
<div class="minicart-table">
<table class="views-table">
<tbody>
<tr>
<td class="views-field-field-product-image">text</td>
<td class="tg-yw4l"></td>
</tr>
</tbody>
</table>
</div>
</div>

Use querySelector() for that. It is safe to use. Example:
var anchor = document.querySelector(".cart-contents a:first-child");
console.log(anchor.getAttribute("href"));
<div class="cart-contents">
<div class="minicart-table">
<table class="views-table">
<tbody>
<tr>
<td class="views-field-field-product-image">text</td>
<td class="tg-yw4l"></td>
</tr>
</tbody>
</table>
</div>
</div>
Also, here is how to fix your code:
for (var i = 0, row; row = this.itemsTable.rows; i++) {
for (var j = 0, col; col = row[i].cells; j++) {
console.log(col[j].getElementsByTagName("a")[0].getAttribute("href"));
}
}

Related

Add columns to a new table row in JQuery

I have the following html:
<table id='myTable'>
<tbody>
<tr>
<td id=col1">12</td>
<td id=col2">55</td>
<td id=col3">142</td>
<td id=col4">7</td>
</tr>
</tbody>
</table>
I would like to use JQuery to append everything after column 3 (col3) to a new row. Ideally I would end up with something like this:
<table id='myTable'>
<tbody>
<tr>
<td id=col1">12</td>
<td id=col2">55</td>
<td id=col3">142</td>
</tr>
<tr>
<td id=col4">7</td>
</tr>
</tbody>
</table>
Any ideas how this could be achieved? I have tried a few things but haven't been able to get it working.
You could define a generic redistribution function, that takes as argument the desired number of columns, and which just fills up the rows with content from top to bottom, using that number of columns.
It could even be a jQuery plugin:
$.fn.redistribute = function(maxNumCols) {
if (maxNumCols < 1) return;
$(this).each(function () {
let cells = Array.from($("td", this));
let $tr = $("tr", this);
let rowCount = Math.ceil(cells.length / maxNumCols);
for (let i = 0; i < rowCount; i++) {
let $row = i >= $tr.length ? $("<tr>").appendTo(this) : $tr.eq(i);
$row.append(cells.splice(0, maxNumCols));
}
});
}
// I/O management
function alignTable() {
let cols = +$("input").val(); // Get desired number of columns
$("#myTable").redistribute(cols); // Apply to table
}
// Refresh whenever input changes
$("input").on("input", alignTable);
// Refresh on page load
alignTable();
table { border-collapse: collapse; border: 2px solid }
td { border: 1px solid; padding: 4px }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Desired number of columns: <input type="number" size="3" value="4" min="1">
<table id='myTable'>
<tbody>
<tr>
<td>12</td>
<td>55</td>
<td>142</td>
<td>7</td>
<td>20</td>
<td>410</td>
<td>99</td>
</tr>
</tbody>
</table>
Here is a version with one extra statement that sets the colspan on the very last td element so it occupies the remaining columns in the last row:
$.fn.redistribute = function(maxNumCols) {
if (maxNumCols < 1) return;
$(this).each(function () {
let cells = Array.from($("td", this));
let $tr = $("tr", this);
let rowCount = Math.ceil(cells.length / maxNumCols);
for (let i = 0; i < rowCount; i++) {
let $row = i >= $tr.length ? $("<tr>").appendTo(this) : $tr.eq(i);
$row.append(cells.splice(0, maxNumCols));
}
$("td", this).last().attr("colspan", rowCount * maxNumCols - cells.length + 1);
});
}
// I/O management
function alignTable() {
let cols = +$("input").val(); // Get desired number of columns
$("#myTable").redistribute(cols); // Apply to table
}
// Refresh whenever input changes
$("input").on("input", alignTable);
// Refresh on page load
alignTable();
table { border-collapse: collapse; }
td { border: 1px solid; padding: 4px }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Desired number of columns: <input type="number" size="3" value="4" min="1">
<table id='myTable'>
<tbody>
<tr>
<td>12</td>
<td>55</td>
<td>142</td>
<td>7</td>
<td>20</td>
<td>410</td>
<td>99</td>
</tr>
</tbody>
</table>
It sounds like you're still new to jQuery. To give you an idea how to solve your described problem, I have written a solution here. I hope it helps you.
// parameters for splitting
var splitIndex = 3,
splitClass = '.split-columns';
// start the splitting
splitColumnsIntoRows();
function splitColumnsIntoRows() {
var $tables = $(splitClass),
numberTables = $tables.length;
if (numberTables == 0) {
return;
}
for (var i = 0; i < numberTables; i++) {
iterateSplittingRows($($tables[i]).find('tr'));
}
}
function iterateSplittingRows($currentRows) {
var $currentRow,
numberRows = $currentRows.length;
if (numberRows == 0) {
return;
}
for (var i = 0; i < numberRows; i++) {
$currentRow = $($currentRows[i]);
iterateSplittingFields($currentRow, $currentRow.find('th, td'));
}
}
function iterateSplittingFields($currentRow, $currentFields) {
var $newRow,
newRows = [],
childrenLength,
numberFields = $currentFields.length;
if (numberFields == 0) {
return;
}
for (var i = 0; i < numberFields; i++) {
if (i < splitIndex) {
continue;
}
if (i % splitIndex == 0) {
$newRow = $('<tr></tr>');
}
$newRow.append($currentFields[i]);
if (i == numberFields - 1) {
childrenLength = $newRow.children().length;
// fill the row with empty fields if the length does not fit the splitIndex
for (var j = splitIndex; j > childrenLength; j--) {
$newRow.append($('<td></td>'));
}
}
if (
(i >= splitIndex && i % splitIndex == splitIndex - 1)
||
i == numberFields - 1
){
newRows.push($newRow);
}
}
$currentRow.after(newRows);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable" class="split-columns">
<tbody>
<tr>
<td class="col_01">01</td>
<td class="col_02">02</td>
<td class="col_03">03</td>
<td class="col_04">04</td>
<td class="col_05">05</td>
<td class="col_06">06</td>
<td class="col_07">07</td>
<td class="col_08">08</td>
<td class="col_09">09</td>
</tr>
<tr>
<td class="col_10">10</td>
<td class="col_11">11</td>
<td class="col_12">12</td>
<td class="col_13">13</td>
<td class="col_14">14</td>
<td class="col_15">15</td>
<td class="col_16">16</td>
<td class="col_17">17</td>
</tr>
<tr>
<td class="col_19">19</td>
<td class="col_20">20</td>
<td class="col_21">21</td>
<td class="col_22">22</td>
<td class="col_23">23</td>
<td class="col_24">24</td>
<td class="col_25">25</td>
</tr>
</tbody>
</table>

Show calculated arithmetic mean in <td> when the button is clicked

please help me finish this, I'm getting nowhere.
what needs to be done
final results
I've explained in the pictures whats the finish goal.
This is a grade calculator.
There are 3 types of grades.. it should calculate the arithmetic mean for every category and arithmetic mean for all grades no matter which category they are.
Calculated values should be shown on the appropriate block, as shown in the picture.
input[type="number"]{
color : transparent;
text-shadow : 0 0 0 #000;
}
input[type="number"]:focus{
outline : none;
}
</style>
<body>
<div id="stranica" style="display: inline-block; position: left;">
<button type="button" onclick="javascript:dodajocenu();"> Add grade</button>
</div>
<div id="desna" style="display: inline-block; position: absolute; text-align: center;">
<button type="button" onclick=""> Calculate </button>
<br><br>
<table border="1">
<tbody>
<tr>
<td style="width:70px; text-align: center;">Written test</td>
<td style="width:70px; text-align: center;">Essay</td>
<td style="width:70px; text-align: center;">Class Activity</td>
</tr>
<tr>
<td style="text-align: center;"> </td> <!-- insert arithmetic mean of all Writtentest, inside td-->
<td style="text-align: center;"></td> <!-- insert arithmetic mean of all Essay, inside td-->
<td style="text-align: center;"></td> <!-- insert arithmetic mean of all ClassActivity, inside td-->
</tr>
</tbody>
</table>
<br>
<table border="1">
<tbody>
<tr>
<td style="width:140px; text-align: center;">Arithmetic mean of all grades</td>
</tr>
<tr>
<td style="text-align: center;"> </td> <!-- insert arithmetic mean of all numbers-->
</tr>
</tbody>
</table>
</div>
</body>
<script>
var ocena = 0;
var stranica = document.querySelector("#stranica")
function removeElement(obrisi) {
var dugme = obrisi.target;
stranica.removeChild(dugme.parentElement)
}
function dodajocenu() {
ocena++;
//create textbox
var input = document.createElement('input');
input.type = "number";
input.setAttribute("max",5);
input.setAttribute("min",1);
var myParent = document.body;
//Create array of options to be added
var array = ["Written test","Essay","Class Activity"];
//Create and append select list
var selectList = document.createElement('select');
selectList.id = "mySelect";
myParent.appendChild(selectList);
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement('option');
option.value = array[i];
option.text = array[i];
selectList.appendChild(option);
}
//create remove button
var remove = document.createElement('button');
remove.onclick = function(obrisiocenu) {
removeElement(obrisiocenu);
}
remove.setAttribute("type", "dugme");
remove.innerHTML = "-"; //delete
var item = document.createElement('div')
item.classList.add("item")
item.appendChild(input);
item.appendChild(selectList);
item.appendChild(remove);
stranica.appendChild(item)
}
</script>```
var ocena = 0;
function removeElement(obrisi) {
var dugme = obrisi.target;
document.getElementById("stranica").removeChild(dugme.parentElement)
}
function dodajocenu() {
ocena++;
//create textbox
var input = document.createElement('input');
input.type = "number";
input.setAttribute("max", 5);
input.setAttribute("min", 1);
var myParent = document.body;
//Create array of options to be added
var array = ["Kontrolni", "Vezbe", "Aktivnost"];
//Create and append select list
var selectList = document.createElement('select');
selectList.id = "mySelect";
myParent.appendChild(selectList);
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement('option');
option.value = array[i];
option.text = array[i];
selectList.appendChild(option);
}
//create remove button
var remove = document.createElement('button');
remove.onclick = function(obrisiocenu) {
removeElement(obrisiocenu);
}
remove.setAttribute("type", "dugme");
remove.innerHTML = "-"; //delete
var item = document.createElement('div')
item.classList.add("item")
item.appendChild(input);
item.appendChild(selectList);
item.appendChild(remove);
document.getElementById("stranica").appendChild(item)
}
function calcMean() {
var nameList=document.querySelectorAll('#stranica .item #mySelect');
var inputList=document.querySelectorAll('#stranica .item input');
var kontrolniList = [];
var vezbeList = [];
var aktivnostList = [];
var ocenaList = [];
for(var i=0; i< nameList.length; i++){
ocenaList.push(parseInt(inputList[i].value));
if(nameList[i].value=='Kontrolni') {
kontrolniList.push(parseInt(inputList[i].value));
}
else if(nameList[i].value=='Vezbe') {
vezbeList.push(parseInt(inputList[i].value));
}
else if(nameList[i].value=='Aktivnost') {
aktivnostList.push(parseInt(inputList[i].value));
}
}
document.getElementById("kontrolni").innerHTML=avg(kontrolniList);
document.getElementById("vezbe").innerHTML=avg(vezbeList);
document.getElementById("aktivnost").innerHTML=avg(aktivnostList);
document.getElementById("ocena").innerHTML=avg(ocenaList);
}
function avg( arr ) {
var total = 0, i;
for (i = 0; i < arr.length; i += 1) {
total += arr[i];
}
return total / arr.length;
}
<div id="stranica" style="display: inline-block; position: left;">
<button type="button" onclick="javascript:dodajocenu();"> Dodaj ocenu</button>
</div>
<div id="desna" style="display: inline-block; position: absolute; text-align: center;">
<button type="button" onclick="javascript:calcMean();"> Izracunaj prosek</button>
<br><br>
<table border="1">
<tbody>
<tr>
<td style="width:70px; text-align: center;">Kontrolni</td>
<td style="width:70px; text-align: center;">Vezbe</td>
<td style="width:70px; text-align: center;">Aktivnost</td>
</tr>
<tr>
<td id="kontrolni" style="text-align: center;"> </td>
<td id="vezbe" style="text-align: center;"></td>
<td id="aktivnost" style="text-align: center;"></td>
</tr>
</tbody>
</table>
<br>
<table border="1">
<tbody>
<tr>
<td style="width:140px; text-align: center;">Zakljucna ocena</td>
</tr>
<tr>
<td id="ocena" style="text-align: center;"> </td>
</tr>
</tbody>
</table>
</div>
Hope this will work.

display style for table row to stay aligned with header

I have a table and using javascript I give the user the option to remove table rows from the table by putting the display style to none.
If the user wants to see the rows again, I need to put the display style away from none and my problem is that I don't know what style to use. I thought table-row-group is the most sensible, but it messes up the rows...
I created a fiddle here and copied the code below
https://jsfiddle.net/b2s3dpo5/#&togetherjs=7EwfsBJIfw
<fieldset style="display: inline-block;">
<div style="display: inline-block;">
<input type="checkbox" name="{{ category.name }}" id="category" checked> remove rows
</div>
</fieldset>
<div class="panel panel-default col-xs-12">
<table class="table table-striped">
<thead>
<tr>
<th><strong>ID</strong></th>
<th><strong>test test test</strong></th>
<th><strong>Institute/Organisation</strong></th>
<th><strong>test deadline test</strong></th>
</tr>
</thead>
<tbody>
<tr class="category">
<th class="col-xs-1" scope="row">
test
</th>
<td class="col-xs-5">
test
</td>
<td class="col-xs-4">
test
</td>
<td class="col-xs-2">
test
</td>
</tr>
</tbody>
</table>
</div>
and the necessary javascript
document.getElementById('category').onclick = function() {
toggleSub_by_class(this, 'category');
};
function toggleSub_by_class(box, select_class) {
// get reference to related content to display/hide
var el = document.getElementsByClassName(select_class);
var flag;
if (box.checked) {
for (var i = 0, j = el.length; i < j; i++) {
el[i].style.display = 'table-row-group';
}
} else {
for (var i = 0, j = el.length; i < j; i++) {
var classList = el[i].className.split(' ')
flag = 0
for (var h = 0, k = classList.length; h < k; h++) {
if (document.getElementById(classList[h])) {
if (document.getElementById(classList[h]).checked) {
flag = 1
}
}
}
if (flag == 0) {
el[i].style.display = 'none';
}
}
}
}
Try visibility:hidden or height:0px or both.
I figured it out myself... the correct display style is empty
el[i].style.display = '';
that works fine for me
carl
First off, for readability purposes, try to create more concise headers when you share it with the rest of the community (although I understand that this is not a big deal).
I would try
visibility:hidden

how to remove and re-order cells in a table in JavaScript

As per question how could I remove empty cells and bring cells with data on top of the table in JavaScript/Prototype, basically all cells with data will be at the top and then empty cells should be removed.
<table>
<tr class="row">
<td class="c1">Cell1</td>
<td class="c2">Cell2</td>
</tr>
<tr class="row">
<td class="c1">Cell1</td>
<td class="c2"></td>
<td class="c3">Cell3</td>
</tr>
<tr class="row">
<td class="c1">Cell1</td>
<td class="c2">Cell2</td>
<td class="c3"></td>
</tr>
</table>
Cell1 Cell2 Cell1 Cell2 Cell3
Cell1 Cell3 ---> Cell1 Cell2
Cell1 Cell2 Cell1
Thanks
In the end it's a little bit of an algorithm that needs to be coded.
I simply used DOM-functionality as I'm not that familiar with jQuery or other frameworks, but I think you can figure out the idea of the algorithm. It shouldn't be too hard to convert it.
<html>
<head>
<script type="text/javascript">
function init() {
var table = document.getElementsByTagName("table")[0];
var trs = table.getElementsByTagName("tr");
var data = [];
var rows, columns;
// run through all TRs and TDs and collect the data into an array without
// empty slots
for (var r = 0; r < trs.length; r++) {
var tds = trs[r].getElementsByTagName("td");
for (var d = 0; d < tds.length; d++) {
if (tds[d].innerHTML) {
data[d] = (data[d] || []).concat(tds[d].innerHTML);
}
}
}
// the tricky thing now is to convert the X/Y alignment of the
// elements in data into a Y/X one for the table
columns = data.length; // target table will have this many columns
rows = data[0].length; // target table will have this many rows
table = document.createElement("table");
for (var r = 0; r < rows; r++) {
var tr = document.createElement("tr");
for (var c = 0; c < columns; c++) {
var td = document.createElement("td");
td.innerHTML = data[c][r] || "";
tr.appendChild(td);
}
table.appendChild(tr);
}
document.body.appendChild(table);
}
</script>
</head>
<body onload="init()">
<table>
<tr class="row">
<td class="c1">Cell1</td>
<td class="c2">Cell2</td>
</tr>
<tr class="row">
<td class="c1">Cell1</td>
<td class="c2"></td>
<td class="c3">Cell3</td>
</tr>
<tr class="row">
<td class="c1">Cell1</td>
<td class="c2">Cell2</td>
<td class="c3"></td>
</tr>
</table>
</body>
</html>
The output matches your request.
window.onload = function() {
var tds = document.getElementsByTagName("td");
for(var i=0; i<tds.length; i++) {
if(tds[i].innerHTML == "") {
tds[i].parentNode.removeChild(tds[i]);
}
}
};

how to pass html table values to excel sheet cells

function toExcel(tableID)
{
var detailsTable = document.getElementById(tableID);
var oExcel = new ActiveXObject("Scripting.FileSystemObject");
var oBook = oExcel.Workbooks.Add;
var oSheet = oBook.Worksheets(1);
for (var y=0;y<detailsTable.rows.length;y++)
{
for (var x=0;x<detailsTable.rows(y).cells.length;x++)
{
oSheet.Cells(y+1,x+1) =detailsTable.rows(y).cells(x).innerText;
}
}
oExcel.Visible = true;
oExcel.UserControl = true;
}
As I posted here. However, can't test it myself. So let me know, if it works :)
<html>
<head>
<script type="text/javascript">
function CreateExcelSheet() {
var x = myTable.rows;
var xls = new ActiveXObject("Excel.Application");
xls.visible = true;
xls.Workbooks.Add;
for (i = 0; i < x.length; i++) {
var y = x[i].cells;
for (j = 0; j < y.length; j++) {
xls.Cells( i+1, j+1).Value = y[j].innerText;
}
}
}
</script>
</head>
<body>
<form>
<input type="button" onclick="CreateExcelSheet()" value="Create Excel Sheet">
</form>
<table id="myTable" border="1">
<tr>
<td>Name</td>
<td>Age</td>
</tr>
<tr>
<td>Shivani</td>
<td>25</td>
</tr>
<tr>
<td>Naren </td>
<td>28</td>
</tr>
<tr>
<td>Logs</td>
<td>57</td>
</tr>
<tr>
<td>Kas</td>
<td>54</td>
</tr>
<tr>
<td>Sent</td>
<td>26</td>
</tr>
<tr>
<td>Bruce</td>
<td>7</td>
</tr>
</table>
</body>
</html>
<script language="javascript">
function runApp()
{
var Excel, Book;
var x=myTable.rows;
Excel = new ActiveXObject("Excel.Application");
Excel.Visible = true;
Book = Excel.Workbooks.Add();
for (i = 0; i < x.length; i++)
{
var y = x[i].cells;
for (j = 0; j < y.length; j++)
{
Book.ActiveSheet.Cells( i+1, j+1).Value = y[j].innerText;
}
}
}
</script>
And the HTML CODE
<table id="myTable">
....
</table>
<form>
<input type="button" onclick="runApp()" value="Export">
</form>
This should do the job.

Categories