JavaScript -- reading a table - javascript

This is a function that, when passed a table as an argument, applies a different style color to alternating rows to improve readability. i.e. first row is dark grey, second row is light grow, third row is dark grey etc.
As mentioned, it gets passed the whole table as an argument. None of the rows have ids. Starting at this line var aTBODY = oTable.getElementsByTagName("tbody");, I understand what is happening. Namely, it gets the table body and then all the rows within it and stripes them alternately.
1) But what is happening exactly in the first five lines of the program? The comments don't explain it clearly for me.
2) does looping over a table length (i.e idArray.length) create an array of rows? what is happening with var id = idArray[indx]; ?
3) When it says, in the comments, get the table that corresponds to this id, using the code var oTable = document.getElementById(id) why is this a necessary step? what is happening?
thank you if you can explain
function createStripedTable(idArray) {
// for each table ID that we're given, stripe all the rows.
for (var indx = 0; indx < idArray.length; indx++) {
var id = idArray[indx];
// get the table that corresponds to this ID
var oTable = document.getElementById(id);
if (oTable == null)
return;
// get its table body, which contains all the TR tags
var aTBODY = oTable.getElementsByTagName("tbody");
// set the CSS class for each one of the TR tags
for (var i = 0; i < aTBODY.length; i++) {
// get an array of all the TR tags in the TBODY
var aTR = aTBODY[i].getElementsByTagName("tr");
for (var j = 0; j < aTR.length; j++) {
// the % operator divides the given number by another
// and returns the remainder. This is how we alternate the
// rows.
aTR[j].className = (j % 2 == 1) ? "stripe1" : "stripe2";
}
}
}
}
Here's the code that's calling it.
function() {createStripedTable(new Array("MSFTQuotes"))
Here's an excerpt of the one and only one table that is passed.
<body>
<table id="MSFTQuotes">
<thead>
<tr>
<th colspan="7" align="center">
<span class="TableTitle">Stock Activity for Aug 5, 2008 - Nov 5, 2008 </span>
</th>
</tr>
<tr>
<th align="center" width="14%">
<div align="right" class="style5">
Date</div>
</th>
<th align="center" width="14%">
<div align="right" class="style5">
Open</div>
</th>
<th align="center" width="14%">
<div align="right" class="style5">
High</div>
</th>
<th align="center" width="14%">
<div align="right" class="style5">
Low</div>
</th>
<th align="center" width="14%">
<div align="right" class="style5">
Close</div>
</th>
<th align="center" width="14%">
<div align="right" class="style5">
Volume</div>
</th>
<th align="center" width="14%">
<div align="right" class="style5">
Adj Close</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td align="right">
5-Nov-08
</td>
<td align="right">
29.21
</td>
<td align="right">
29.36
</td>
<td align="right">
29.03
</td>
<td align="right">
29.31
</td>
<td align="right">
95,337,696
</td>
<td align="right">
29.31
</td>

The function accepts an array of id values corresponding to table elements. It loops through those IDs and does its striping work on all of the tbody elements within the tables.
Somewhat more annotated (see TJC:s):
function createStripedTable(idArray) {
// for each table ID that we're given, stripe all the rows.
// TJC: Loop through all of the IDs in the given array
for (var indx = 0; indx < idArray.length; indx++) {
// TJC: Get the ID value for index `indx` in the array
var id = idArray[indx];
// get the table that corresponds to this ID
var oTable = document.getElementById(id);
if (oTable == null) // TJC: Invalid ID, ignore it
return;
// get its table body, which contains all the TR tags
// TJC: Get the `tbody`s under the table. One table
// can have multiple `tbody` elements.
var aTBODY = oTable.getElementsByTagName("tbody");
// set the CSS class for each one of the TR tags
for (var i = 0; i < aTBODY.length; i++) {
// get an array of all the TR tags in the TBODY
// TJC: It's actually a NodeList, but you can largely
// treat it as an array
var aTR = aTBODY[i].getElementsByTagName("tr");
for (var j = 0; j < aTR.length; j++) {
// the % operator divides the given number by another
// and returns the remainder. This is how we alternate the
// rows.
aTR[j].className = (j % 2 == 1) ? "stripe1" : "stripe2";
}
}
}
}
The good news is that IE9 finally supports the nth-child pseudo-class, so someday you'll be able to stop doing this with code.

idArray is an array of all IDS for more than one table. This function will change the alternate rows for each of the tables whose id is in idArray.
The outer loop is iterating through ids. The first five lines inside the loop are assuming they are ids of tables, and fetching the contents of the table element corresponding to each ID.
The next five lines in the loop then fetch the table body contents and change the css class of alternate rows.

Add these lines before the first for loop in the code
var tabarray=new Array();
tabarray.push(thetableidYoupassed);
idArray=tabArray
'thetableidYoupassed' is the actual argument with which you called the function 'createStripedTable'
Keep the rest of the code as it is...This should work fine...

Your method accepts an array of table IDs. So all the tables need to have IDs.
function createStripedTable(idArray) { //idArray is an array of table IDs
Then it loops through them and gets the ID one by one
for (var indx = 0; indx < idArray.length; indx++) {
var id = idArray[indx]; //this is the ID of a table
Then it checks whether the table actually exists in the DOM or not
var oTable = document.getElementById(id); //IF the table with a matching ID is not found, you get NULL
if (oTable == null)
return; //no table that matches the ID? return
Ideally, that line should be continue or something similar. Because in this instance. If you pass your method an array like ['table1', 'table2', 'faketable', 'table3'], your method won't strip table3 because it never gets there in the array (because of the return)

Related

Filter multiple tables using query string with javascript

first I'm sorry if at some point I express myself badly, English is not my native language. I am developing an application in which the user sends 2 values through a form and in another page I use one of those data (string with comma separated options) to show a specific table and hide the others, and with the second data (Integer) I show one of the rows of that table.
What I already have:
I have the form and send the data through the Query String, I capture that data, I assign a variable to the integer and to the text string I separate it by commas and create an array.
URL Example: app.tables.example/?id=123&ops=option1%2c+option2
//Read parameters sent by form
const param = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop)
});
//Assign integer to a variable
let num = param.id;
//Assign options to a variable
let op = param.ops;
//Separate string with commas
let opsplit = op.split(',');
Up to here everything is perfect, I can print all the variables without any problem, now I need to compare the array with the id of each table, show the one that corresponds and hide the others. (The id of the tables is the same that user passes with the text string).
The tables look something like this:
<div id="option1" class="table-1">
<table width="100%">
<thead>
<tr>
<th align="left">Option1</th>
<th align="left">Integer</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Number</td>
<td align="left">Info</td>
</tr>
<tr>
<td align="left">1</td>
<td align="left">textblock</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">textblock</td>
</tr>
</tbody>
</table>
</div>
//As you can see the id of each table corresponds to what the user chose
<div id="option2" class="table-1">
<table width="100%">
<thead>
<tr>
<th align="left">Option2</th>
<th align="left">Integer</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Number</td>
<td align="left">Info</td>
</tr>
<tr>
<td align="left">1</td>
<td align="left">textblock</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">textblock</td>
</tr>
</tbody>
</table>
</div>
The problem:
I'm supposed to use the array elements in a "for" loop and compare them with the id of each table, then show that table and hide others, but I don't know exactly how to do it.
function myFunction() {
var input, filter, table, tr, td, i, y, txtValue;
for (r = 0; r<opsplit.length; r++){
input = opsplit[r];
filter = function(x){
return x.toUpperCase();
};
opsplit = opsplit.map(filter);
}
//When I test this, it does not return any value,
//innerHTML error
for(y = 0; y<opsplit.length; y++){
table = document.getElementById(opsplit[y]).innerHTML;
//I use this section to test, it should show me the row,
//but since the previous loop failed, it does nothing.
// What I really need is to show the whole
// table where this data is located and hide the other tables.
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
}
myFunction();
I am really stuck at the moment and would appreciate any help. What is the correct way to use the string array, and how can I hide the tables that the user does not need?
Ok, thanks to those who took the time to write a comment, but I found the solution, I had to convert the form data to a string and an integer. Then I was able to compare that string to the classes id. I am writing the answer in case anyone finds it useful.
//Read parameters sent by form
const param = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop)
});
//Assign number to a variable
let num = param.id;
//Convert to integer
let numint = parseInt(num);
//Assign options to a variable
let op = param.ops;
//Convert to String
let opstr = op.string();
//Separate string with commas
let opsplitstr = opstr.split(',');
//Assign class to a variable
tableclass = document.getElementsByClassName('table-1');
//Compare table class ids with string array
if (opsplitstr[0] == tableclass[0].id{
}
//We need a loop if we need compare all elements
TLDR: The URL does not send information about the data type, so I had to read it and convert it according to my need.

Getting a checkbox from a table field

Good afternoon, below is the code in it I am getting fields from my table. The 0 field contains a checkbox, how can I find out if it is checked or not(true or false)? You need to change this line: console.log (td.item (f));
var table = document.getElementsByClassName("table-sm");
for (var i = 0; i < table.length; i++) {
var tr = table.item(i).getElementsByTagName("tr");
for (var j = 0; j < tr.length; j++) {
var trr = tr.item(j);
var td = tr.item(j).getElementsByTagName("td");
for (var f = 0; f < td.length; f++) {
if (f === 0) console.log(td.item(f));
console.log(td.item(f).innerText);
}
}
}
Firstly, please learn about JavaScript Table API is much better than just making complex for-loops.
Next time please add full code (HTML/JavaScript) so people can help you.
Now let's fix your code.
Suppose we have this table
<table class="table-sm" id="myTable">
<thead>
<tr>
<th>Checkbox</th>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="selected[]" checked /></td>
<td>1</td>
<td>Mohammed</td>
</tr>
<tr>
<td><input type="checkbox" name="selected[]" /></td>
<td>2</td>
<td>Ali</td>
</tr>
</tbody>
</table>
and we want to get the first item of each rows, and check whether the checkbox is checked or not.
We can do it easly using JS Table APIs.
Get the table by it's ID.
var table = document.getElementById("myTable");
Get the table rows
I use Array.from() to convert HTMLCollection to normal array, so I can use Array APIs (Like .forEach).
var rows = Array.from(table.rows);
Loop into table rows, and get cells of each row.
rows.map((row) => {
var cells = Array.from(row.cells);
// TODO add logic here.
});
Get the firstChild of first cell.
rows.map((row) => {
var cells = Array.from(row.cells);
if (Array.isArray(cells) && cells.length > 0) {
var firstChild = cells[0].firstChild;
console.log(firstChild.checked);
}
});
Live Example

How can I make sure a specific string exists in every table row using JavaScript?

I'm a beginner at JavaScript and haven't been able to figure this out...
I need to check each row of a table to see if the string "Business Cards" exists in each row. If EVERY row contains this string, I'll proceed with option A, but if even one row doesn't contain the string, I'll stop checking and proceed with option B.
Here is an idea of what the table looks like in HTML (although the number of rows and products in each row will vary, since they're dynamically generated):
<table class="rgMasterTable" border="0" id="ctl00_cphMainContent_dgShippingItems_ctl00" style="width:100%;table-layout:auto;empty-cells:show;">
<thead>
<tr>
<th scope="col" class="rgHeader" style="text-align:center;">Name</th>
<th scope="col" class="rgHeader" style="text-align:center;">No. of Units</th>
</tr>
</thead>
<tbody>
<tr class="rgRow" id="ctl00_cphMainContent_dgShippingItems_ctl00__0" style="text-align:center;">
<td style="width:250px;">
Business Cards - TEST - CA Back
</td>
<td style="width:100px;">
250 Business Cards
</td>
</tr>
<tr class="rgAltRow" id="ctl00_cphMainContent_dgShippingItems_ctl00__1" style="text-align:center;">
<td style="width:250px;">
Business Cards - Joint Venture - TEST
</td>
<td style="width:100px;">
250 Business Cards
</td>
</tr>
</tbody>
</table>
And here's my attempt at the code. I'm trying to make use of the fact that the tr id will always have the index (eg: "ctl00_cphMainContent_dgShippingItems_ctl00__0" for the first row, "ctl00_cphMainContent_dgShippingItems_ctl00__1" for the second, etc), but maybe there's an easier way to do this?
var businessCardItem = 'Business Cards';
var orderItemCount = $('#ctl00_cphMainContent_dgShippingItems_ctl00 tr').length;
var onlyBusinessCards = true;
for (var i = 0; i <= orderItemCount; i++) {
if($('#ctl00_cphMainContent_dgShippingItems_ctl00__' + i).text().indexOf(businessCardItem) >= 0) {
return onlyBusinessCards;
}
else {
onlyBusinessCards = false;
return onlyBusinessCards;
break;
}
}
if (onlyBusinessCards == true) {
//Option A
}
else {
//Option B
}
Any help would be appreciated! Let me know if any more detail or clarification is needed!
Count how many rows contain "Business Cards" and compare to the number of rows:
Note: only count rows within tbody
var table = $("#ctl00_cphMainContent_dgShippingItems_ctl00");
var rows = $("tbody tr",table).length;
var rowsWithBC = $("tbody tr:contains(Business Cards)",table).length;
if( rows == rowsWithBC ) {
// Option A
} else {
// Option B
}

td background colouring applied to complete column rather to a single cell

I've below html.
<table border="1" class="myTable">
<tr>
<th class="cname">Component</th>
<th class="pname">Properties</th>
<th class="sname">lqwasb02</th>
</tr>
<tr>
<td class="cname">EMWBISConfig</td>
<td class="pname">reEvaluationTimer</td>
<td class="pvalue">every 1 hour without catch up</td>
</tr>
<tr>
<td class="cname">CalculateCategoryMediaInfoService</td>
<td class="pname">scheduled</td>
<td class="pvalue">yes</td>
</tr>
<tr>
<td class="cname">EMWBISScheduler</td>
<td class="pname">scheduled</td>
<td class="pvalue">no</td>
</tr>
<tr>
<td class="cname">CatalogTools</td>
<td class="pname">loggingDebug</td>
<td class="pvalue">false</td>
</tr>
</table>
Below is the jquery I've written.
$(document).ready(function(){
var list = ['every 1 hour without catch up','yes','yes','false'];
$.each(list,function(index,value){
//alert(index+' : '+value);
});
var idx;var list2 = new Array();
// Find index of cell with 'lqwasb02'
$('.myTable th').each(function(index) {
if ($(this).text() === 'lqwasb02') idx = index;
});
// Loop through each cell with the same index
$('.myTable tr').each(function() {
if($(this).find('td:eq('+idx+')').text() !=""){
list2.push($(this).find('td:eq('+idx+')').text());
}
}); var idx2 = [];
for(var x=0;x<list2.length;x++){
if(list[x]===list2[x]){
//console.log(list[x]);
}else{
console.log('mismatched : '+list[x]);
$('.myTable tr').each(function() {
$(this).find('td:eq('+x+')').css("background-color", "red");
});
idx2.push(x);
}
}
});
I'm trying to compare values in list with values in lqwasb02 column and if it finds the difference, it should highlight the background of td cell in red colour.
Current issue with jquery code, it is highlighting the complete column.
Can someone please help me where I'm getting wrong? If possible, please pass on the recommended solutions.
Many Thanks in advance.
The problem is that in your .find you are returning multiple elements that it's selector matches. So as opposed to storing the text value for your td elements in the second array, just store the actual td element, compare it's text, and then you can assign the background color directly to the element as opposed to finding it again via it's index:
$(document).ready(function(){
var list = ['every 1 hour without catch up','yes','yes','false'];
$.each(list,function(index,value){
//alert(index+' : '+value);
});
var idx;var list2 = new Array();
// Find index of cell with 'lqwasb02'
$('.myTable th').each(function(index) {
if ($(this).text() === 'lqwasb02') idx = index;
});
// Loop through each cell with the same index
$('.myTable tr').each(function() {
if($(this).find('td:eq('+idx+')').text() !=""){
list2.push($(this).find('td:eq('+idx+')')); // <-- Store the object here, not it's text value.
}
});
var idx2 = [];
for(var x=0; x < list2.length; x++){
if(list[x]===list2[x].text()) { // <-- compare list[x] to the text value of list2[x]
//console.log(list[x]);
} else {
list2[x].css("background-color", "red"); // <-- no find or selector needed, just apply it to the object you stored earlier.
};
idx2.push(x);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1" class="myTable">
<tr>
<th class="cname">Component</th>
<th class="pname">Properties</th>
<th class="sname">lqwasb02</th>
</tr>
<tr>
<td class="cname">EMWBISConfig</td>
<td class="pname">reEvaluationTimer</td>
<td class="pvalue">every 1 hour without catch up</td>
</tr>
<tr>
<td class="cname">CalculateCategoryMediaInfoService</td>
<td class="pname">scheduled</td>
<td class="pvalue">yes</td>
</tr>
<tr>
<td class="cname">EMWBISScheduler</td>
<td class="pname">scheduled</td>
<td class="pvalue">no</td>
</tr>
<tr>
<td class="cname">CatalogTools</td>
<td class="pname">loggingDebug</td>
<td class="pvalue">false</td>
</tr>
</table>
$('.myTable tr').each(function() {
$(this).find('td:eq('+x+')').css("background-color", "red");
});
this piece of code assign a background colour to each cell of index 'x' for each rows (each cells of index x of each table rows represent a column).
You have to select only the rows which contains the cells you want to colour.
Here is how i would have approached solving this issue:
$(document).ready(function(){
var list = ['every 1 hour without catch up','yes','yes','false'];
var colIndex = findColIndex('lqwasb02');
// Loop over table rows
$('tr').each(function(){
// Look up cell with specific index
var $cell = $(this).find('td').eq(colIndex);
// Check if the text of the cell is not present in the list and do smth
if ($.inArray($cell.text(), list) === -1) {
$cell.css('background', 'red')
}
});
});
// helper function to find the index of column by text in the header
function findColIndex (headerText) {
var $col = $('.myTable th:contains(' + headerText + ')');
return $('.myTable th').index($col);
}
https://jsbin.com/fafegi/1/edit?js,output

javascript to loop through table rows with a classname

Here is the following table code and I want to store all TD values into an Array.
<tr class="item-row">
<td class="item-name"><textarea>Item</textarea></td>
<td class="description"><textarea>Item</textarea></td>
<td><textarea class="cost">$0.00</textarea></td>
<td><textarea class="qty">0</textarea></td>
<td><span class="price">$0.00</span></td>
</tr>
<tr class="item-row">
<td class="item-name"><textarea>Item</textarea></td>
<td class="description"><textarea>Item</textarea></td>
<td><textarea class="cost">$0.00</textarea></td>
<td><textarea class="qty">0</textarea></td>
<td><span class="price">$0.00</span></td>
</tr>
For this I have written this following code:
function checkForm() {
var table = document.getElementsByClassName("item-row");
var arr = new Array();
for (var i = 0, row; row = table.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
arr.push(row.cells[j].val);
}
}
}
But this gives me no output...I am new to javascript so may be am missing something in big time.
Your code is almost right, the thing is that rows property work for tables not for trs so you have to take a table instead of the tr directly.
The other thing is that getElementsByClassName returns an array of your elements so you have to use [index] to get your element.
The last thing is that to get the value for the cell you can't use val, so use firstChild to get the child and value to get the value as in the code, or better as #pawel suggest directly cell.textarea :)
Try with this code:
function checkForm() {
var table = document.getElementsByClassName("yourTable")[0];
var arr = new Array();
for (var i = 0, row; row = table.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
arr.push(row.cells[j].firstChild.value);
}
}
console.log(arr);
}
<table class="yourTable">
<tr class="item-row">
<td class="item-name"><textarea>Item</textarea></td>
<td class="description"><textarea>Item</textarea></td>
<td><textarea class="cost">$0.00</textarea></td>
<td><textarea class="qty">0</textarea></td>
<td><span class="price">$0.00</span></td>
</tr>
<tr class="item-row">
<td class="item-name"><textarea>Item</textarea></td>
<td class="description"><textarea>Item</textarea></td>
<td><textarea class="cost">$0.00</textarea></td>
<td><textarea class="qty">0</textarea></td>
<td><span class="price">$0.00</span></td>
</tr>
</table>
<input type="button" onclick="checkForm();" value="check form"/>
Hope this helps,
What you have is a good first effort for being new to JavaScript, but, yes, there are quite a few items that need updating. :)
Here is what you would need to do what you are trying to do:
function checkForm() {
var rows = document.getElementsByClassName("item-row");
var arr = new Array();
for (i = 0; i < rows.length; i++) {
var cols = rows[i].getElementsByTagName("td");
for (j = 0; j < cols.length; j++) {
arr.push(cols[j].textContent);
}
}
}
You need to cycle through each row . . . the easiest way to do this by going from i = 0 to i < rows.length in your for loop.
Once you have a row, you need to gather all of the columns in the row, by finding all of the <td> elements (var cols = rows[i].getElementsByTagName("td"););
Then, you loop through each of those, just like you did with the rows (j = 0 to j < cols.length
Finally, to get the text contained in each td, you use the textContent property . . . values (i.e., the value property) are used only for <input> elements
There were a couple of syntax errors in there, too (you used , instead of ;, when building your for loop and you used val instead of value, when attempting to get the td content), but that was all that I saw.
Edit: I'm also assuming that you just did not paste your <table> tags in when you added your HTML, but, if you didn't your <tr> tags must be inside a <table.
Edit 2: My solution also skips the looking at the tags inside the <td> elements, since they are not standard (4 contain <textarea> inputs and the 5th a <span>). If you want to go down one more level of detail, you could use .value on the textareas and (again) .textContent on the <span>. By using .textContent one level up, you are ignoring all HTML tags insid the <td> tags and returning only the text.

Categories

Resources