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);
}
}
Related
I am creating a web app with Django and I require some Javascript for changing styles of dynamically generated elements. I have simplified the code to just static html and javascript.
Goal:
The code causing problems is acting on detail pages.
There are many detail pages, each representing data from a given database entry.
Each page will have 1 or more table, depending on how many protein names the database entry has.
For each table, I want to change the colour of the entry for the protein name in the table heading as well as the entry for the example_id.
Attempt:
I am using javascript to capture the example_id from the top level heading and the protein names from the table headings.
I am then capturing the nodelist of table rows and iterating through, looking for entries that match either the protein name or the example_id.
Problem:
When iterating over the nodelist of protein names taken from the table headers in a nested loop the page never loads.
HTML:
<html>
<body>
<h1 class="msaIdCatcher">Protein Record #example_id</h1>
<h2>Multiple Sequence Alignment</h2>
<h3 class= "msaProtNameCatcher">Protein_name1</h3>
<p>The following is a multiple sequence alignment (MSA) of all sequences predicted to be Protein_name1 sequences.</p>
<table>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id1</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>Protein_name1</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id3</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>example_id</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id4</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
</table>
<h3 class="msaProtNameCatcher">Protein_name2</h3>
<p>The following is a multiple sequence alignment (MSA) of all sequences predicted to be Protein_name2 sequences.</p>
<table>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id1</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id2</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id3</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>example_id</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id4</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>Protein_name2</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
</table>
</body>
</html>
var idTitle = document.getElementsByClassName("msaIdCatcher");
id = idTitle[0].innerHTML;
id = id.replace("Protein Record #", "");
//Get protein_names from table headers
proteinnameElements = document.getElementsByClassName("msaProtNameCatcher")
//Get table rows
var sequenceidrowElements = document.getElementsByClassName("sequenceidrow");
//Loop through table rows
for (var i = 0; i < sequenceidrowElements.length; i++) {
//Get sequence id
var sequenceidElement = sequenceidrowElements[i].getElementsByClassName("sequenceid");
idElement = sequenceidElement[0].innerHTML
//Check if ID is ID from page heading
if (idElement == id) {
//Get sequence element and change colour of ID and sequence elemnt
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "#b80090";
alignsequenceElement[0].style.color = "#b80090";
}
//Loop through protein names in table headers and Check if ID in table matches protein name
//Then change colour of ID and sequence
for (var i = 0; i < proteinnameElements.length; i++) {
proteinname = proteinnameElements[i].innerHTML
if (idElement == proteinname) {
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "red";
alignsequenceElement[0].style.color = "red";
}
}
}
However, when using a single protein name by making proteinname equal to the innerHTML of the first element proteinnameElements and taking away the loop nesting as follows, the page loads in a fraction of a second.
var idTitle = document.getElementsByClassName("msaIdCatcher");
id = idTitle[0].innerHTML;
id = id.replace("Protein Record #", "");
//Get protein_names from table headers
proteinnameElements = document.getElementsByClassName("msaProtNameCatcher")
proteinname = proteinnameElements[0].innerHTML
//Get table rows
var sequenceidrowElements = document.getElementsByClassName("sequenceidrow");
//Loop through table rows
for (var i = 0; i < sequenceidrowElements.length; i++) {
//Get sequence id
var sequenceidElement = sequenceidrowElements[i].getElementsByClassName("sequenceid");
idElement = sequenceidElement[0].innerHTML
//Check if ID is ID from page heading
if (idElement == id) {
//Get sequence element and change colour of ID and sequence elemnt
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "#b80090";
alignsequenceElement[0].style.color = "#b80090";
}
//Loop through protein names in table headers and Check if ID in table matches protein name
//Then change colour of ID and sequence
if (idElement == proteinname) {
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "red";
alignsequenceElement[0].style.color = "red";
}
}
Can someone help me understand why nesting loops in this way causes such a large difference in runtime and help me find a way to solve my problem?
Thanks!
Your inner loop begins with var i, because of how scoping works in JavaScript, it will be the same i as the outer loop, and it will be changed everytime the inner loop is run (thereby never increasing the outer loop, making it endless); it's like typing this:
var i;
for (i = 0; i < length; ++i)
{
for (i = 0; i < length2; ++i)
{
//...
}
}
Either use a different variable name for the inner loop (j is a common choice), or use the let keyword (which will ensure the variables are locally scoped), this is the let keyword (note that it's relatively recent):
for (let i = 0; i < length; ++i)
{
//...
}
Hope this helps clear things up.
I want to get value like in subject, from cell but that cell have element <a>1</a> and in this element is the value.
I tried something like this:
function filter(gvId) {
var table = document.getElementById(gvId);
for (var c = 1; c < table.rows[2].cells.length; c++) {
for (var r = headerNumber; r < table.rows.length; r++) {
var value = table.rows[r].cells[c].getElementsByClassName("a").innerHTML;
console.log(value); //and it should show me :
//1
//2
//3
//4
}
}
}
<table>
<tbody>
<tr>
<td><a>1</a>
</td>
<td><a>2</a>
</td>
</tr>
<tr>
<td><a>3</a>
</td>
<td><a>4</a>
</td>
</tr>
</tbody>
</table>
Everything works greate without <a> tag inside cell. But now I don't know how to get this value.
In your case, the problem is in a row:
var value = table.rows[r].cells[c].getElementsByClassName("a").innerHTML;
Because you're trying to match an element by class, but not by element tag. Link tag <a> has no className a. Your current code will work fine for: <a class="a">1</a> or <div class="a"></div>.
May be you should try something like querySelector instead? Like:
var value = table.rows[r].cells[c].querySelector('a').innerHTML;
Please, also check the MDN docs about getElementsByClassName and querySelector
UPD: All the code could be simplified:
var contentLinks = table.querySelectorAll('td a');
contentLinks.forEach(function(item) {
var value = item.innerHTML;
console.log(value);
});
Get the text content of an element with .textContent instead of .innerHTML
var value = table.rows[r].cells[c].textContent;
Documentation here and here
I am trying to get the information from my table td's, using javascript. How can i achieve this? I have tried and failed, because i do not exactly understand the JS. So far, i have managed to get one of them to work, which is 'id' but thats just getting info from the db directly, the td values ive been unable to.
echoing the vals in my php update page shows the id val being passed successfully, but none others.
EDIT
Per your last comment I can recommend you use an event listener on all <td> tags and this way you can just get the relevant text of the specific <td> that the user clicked:
var tds = document.querySelectorAll('td');
for (var i = 0; i < tds.length; i++) {
var td = tds[i];
td.addEventListener('click', function(){
console.log(this.innerText)
});
}
<table>
<tr>
<td class="awb">I am the first awb</td>
<td class="awb">I am the second awb</td>
</tr>
<tr>
<td class="differentClass">I am the first differentClass</td>
<td class="differentClass">I am the second differentClass</td>
</tr>
</table>
You are approaching this all wrong...
Instead of this:
var awbno = String(tr.querySelector(".awb").innerHTML);
Do this:
var awbno = document.querySelector(".awb").innerHTML;
Here is a snippet:
var awbno = document.querySelector(".awb").innerHTML;
console.log(awbno);
<table>
<tr>
<td class="awb">Test Text inside a td tag</td>
</tr>
</table>
in order to get the contents of any element using class
let value = document.querySelector('.className').innerHTML;
in order to get the contents of a specific TD
let value = document.querySelector('td.className');
I just started using DataTables and everything works fine when creating the table.
When I display 5, 24, 47 rows in my table, DataTables behaves as I would expect.
But I have this table that has around 700 rows and I get the error in Google Chrome,
"VM9075 dataTables.min.js:24Uncaught TypeError: Cannot set property '_DT_CellIndex' of undefined "
and in IE 9,
"SCRIPT5007: Unable to set value of the property '_DT_CellIndex': object is null or undefined
jquery-1.10.2.min.js, line 4 character 2367"
I don't have jQuery included twice btw.
I'm not sure how to proceed from here.
I tried to use the unminified version of the .js file to debug it more myself but i kept getting an "ext" method or property is undefined and couldn't fix that either.
Any help is appreciated!
I figured it out
The biggest issue was not knowing exactly what this error actually meant.
In my case it meant "the number of every <td> element in your table that is a child of a <tr> element doesn't match the number of <th> elements that are a child of the <thead> element."
My table was being generated by the server, and some of the <tr> elements had 27 <td> children (which was filling the whole width of the table up, but some of the <tr> elements only had 3, 4, or 5, ... <td> child elements which isn't a valid table.
I solved it by adding empty <td> elements in my table for the <tr> elements that lacked the correct number of <td> elements
var makeTableValidObject = {
thisWasCalled: 0,
makeTableValid: function() {
var tableToWorkOn = document.getElementById("table1");
//check the number of columns in the <thead> tag
//thead //tr //th elements
var numberOfColumnsInHeadTag = tableToWorkOn.children[1].children[0].children.length;
var numberOf_trElementsToValidate = tableToWorkOn.children[2].children.length;
//now go through each <tr> in the <tbody> and see if they all match the length of the thead columns
//tbody //all trs//all tds elements
//tableToWorkOn.children[2].children.children);
for(var i = 0; i < numberOf_trElementsToValidate; i++) {
//row my row make sure the columns have the correct number of elements
var tdColumnArray = tableToWorkOn.children[2].children[i].children
var trElementToAppendToIfNeeded = tableToWorkOn.children[2].children[i];
if(tdColumnArray.length != numberOfColumnsInHeadTag) {
//since they don't match up, make them valid
if(tdColumnArray.length < numberOfColumnsInHeadTag) {
//add the necessary number of blank <td> tags to the <tr> element to make this <tr> valid
var tdColumnArrayLength = tdColumnArray.length;
for(var j = 0; j < (numberOfColumnsInHeadTag - tdColumnArrayLength); j++) {
var blank_tdElement = document.createElement("td");
blank_tdElement.id = "validating_tdId" + i + "_" + j;
trElementToAppendToIfNeeded.appendChild(blank_tdElement);
}
}
else {
//TODO: remove <td> tags to make this <tr> valid if necessary
}
}
}
}
};
Edit 1:
It has been awhile and this question is still getting a bunch of views. I have since updated the code.
I replaced the first line of code with the second line to be more general
var numberOfColumnsInHeadTag = tableToWorkOn.children[1].children[0].children.length;
var numberOfColumnsInHeadTag = tableToWorkOn.querySelectorAll('thead')[0].querySelectorAll('th');
Pretty much where ever in the prior code you see the children.children I replaced that with the querySelectorAll(...) Function.
It uses css selectors which makes it amazingly powerful.
stay blessed
Ran into this same issue and implemented this same solution (essentially) in jquery based on Coty's. Hope this helps someone. :)
$( '.table' ).each(function( i ) {
var worktable = $(this);
var num_head_columns = worktable.find('thead tr th').length;
var rows_to_validate = worktable.find('tbody tr');
rows_to_validate.each( function (i) {
var row_columns = $(this).find('td').length;
for (i = $(this).find('td').length; i < num_head_columns; i++) {
$(this).append('<td class="hidden"></td>');
}
});
});
As answered by Coty, the problem lies in the mismatch of td elements generated in the header and body of table.
I'd like to highlight one of the reasons why it can occur (For .Net Users).
If Page numbers are being displayed at the end of gridview, they can disrupt table structure.
Remove AllowPaging="true" from your gridview to solve this.
And no worries because Datatable handles Paging.
you always keep four column but sometimes you will receive or append null td or only one td, td count always match with total column so when you does not have record then make td as following.
<th>No</th>
<th>Name</th>
<th>place</th>
<th>Price</th>
----------------------------------------
<td colspan="4">Data not found.</td>
<td style="display: none;"></td>
<td style="display: none;"></td>
<td style="display: none;"></td>
this error can also be triggered if you try to set options for the responsive extension for more columns than you have.
$( '.table' ).each(function( i ) {
var worktable = $(this);
var num_head_columns = worktable.find('thead tr th').length;
var rows_to_validate = worktable.find('tbody tr');
rows_to_validate.each( function (i) {
var row_columns = $(this).find('td').length;
for (i = $(this).find('td').length; i < num_head_columns; i++) {
$(this).append('<td class="hidden"></td>');
}
});
});
There is a table displaying model entries, with each field designated a unique div id combining a keyword and each row's ID. When the user enters a number in the table's input column, a script is supposed to: get the locations of the cells on the same row; and change the values of two predetermined cells based on the values of the other cells.
It seems that tests are successful until the final updating. I've tried using .val(), .value, and .html(), and the resultant cells go blank, or show 0 if the script is error-free. Would someone please post the correct jQuery command and why it works? Many thanks in advance.
The table:
<table id="dt_Positions" class="table table-striped">
<thead>
<tr>
<th class="text-center">Month</th>
<th class="text-center">Owed</th>
<th class="text-center">Bought</th>
<th class="text-center">Total Position</th>
<th class="text-center">Non-Fixed</th>
<th class="text-center">Fixed</th>
<th class="text-center">Fixed Position</th>
<th class="text-center">Proposed</th>
</tr>
</thead>
<tbody>
#if (Model.Forecasts.Any())
{
foreach (var record in Model.Summaries)
{
<tr>
<td id="nmonth#(record.fID)" align="center">#String.Format("{0:d}", #record.Month)</td>
<td id="ntotal#(record.fID)" align="center">#record.NTotal</td>
<td id="nbought#(record.fID)" align="center">#record.NBought</td>
<td id="ntposition#(record.fID)" align="center">#record.NTotalPosition</td>
<td id="nvariable#(record.fID)" align="center">#record.NVariable</td>
<td id="nfixed#(record.fID)" align="center">#record.NFixed</td>
<td id="nfposition#(record.fID)" align="center">#record.NFPosition</td>
<td id="ninput#(record.fID)" align="center"><input class="nInput" type="number" name="quantity" min="1" max="50000"></td>
</tr>
}
}
</tbody>
</table>
The script:
#section Scripts
{
<script src="~/Scripts/jquery-2.1.3.js"></script>
<script type="text/javascript" language="javascript">
$(function () {
$('[id^=ninput]').keyup(function (e) {
var $id = $(this).attr('id');
var $i = $(this);
var $idNum = $id.slice(6);
var $tp = $('#ntposition' + $idNum);
var $fp = $('#nfposition' + $idNum);
var $nt = $('#ntotal' + $idNum);
var $nh = $('#nbought' + $idNum);
var $f = $('#nfixed' + $idNum);
//The lines below appear to be the hiccup
$tp.val($nh.val() + $i.html() - $nt.val());
$fp.val($nh.val() + $i.html() - $f.val());
debugger;
});
});
</script>
}
EDIT: Examples of ids returning "NaN" are:
ntotal = 29, nbought = 5, ntposition = -24, nvariable = 3, nfixed = 26, nfposition = -21, with all appearing to be int from testing the View, but ntotal, nbought, and nfixed showing "NaN" in the console.log and resulting in "NaN" appearing in the test View after an ninput = 5.
$i is the textbox, so to get its value you need to use $i.val(). The other elements are table cells, so to get or set the values you need .text(), not .val(). However you over complicating code by using id attributes. Instead, remove then and use relative selectors
$('input').keyup(function() { // or $('.nInput').keyup
var i = Number$(this).val());
var cells = $(this).closest('tr').children('td');
var tp = cells.eq(3);
var fp = cells.eq(6);
// Get current cell values as a number
var nt = Number(cells.eq(1).text());
var nh = Number(cells.eq(2).text());
var f = Number(cells.eq(5).text());
// Update totals
tp.text(nh + i - nt);
fp.text(nh + i - f);
});
Side note: The value of var i = $(this).val(); could be null but not sure how you want to handle this - possibly just use
var i = $(this).val();
if (!i) {
return; // don't do any calculations
}
You need to know the difference between val(), text() and html()
val() is for getting and setting values for form elements, input, select etc.
text() is for getting and setting plain unformatted text for non form elements.
html() is for getting and setting inner Html from a node
So what you want is:
$tp.text($nh.text() + $i.val() - $nt.text());
$fp.text($nh.text() + $i.val() - $f.text());
Also be careful as + is both mathematical addition and string concatenation in javascript so you may want to cast your parse the strings to the appropriate number type.