How to get html table td cell value by JavaScript? - javascript

I have an HTML table created with dynamic data and cannot predict the number of rows in it. What I want to do is to get the value of a cell when a row is clicked. I know to use td onclick but I do not know how to access the cell value in the Javascript function.
The value of the cell is actually the index of a record and it is hidden in the table. After the record key is located I can retrieve the whole record from db.
How to get the cell value if I do not know the row index and column index of the table that I clicked?

Don't use in-line JavaScript, separate your behaviour from your data and it gets much easier to handle. I'd suggest the following:
var table = document.getElementById('tableID'),
cells = table.getElementsByTagName('td');
for (var i=0,len=cells.length; i<len; i++){
cells[i].onclick = function(){
console.log(this.innerHTML);
/* if you know it's going to be numeric:
console.log(parseInt(this.innerHTML),10);
*/
}
}
var table = document.getElementById('tableID'),
cells = table.getElementsByTagName('td');
for (var i = 0, len = cells.length; i < len; i++) {
cells[i].onclick = function() {
console.log(this.innerHTML);
};
}
th,
td {
border: 1px solid #000;
padding: 0.2em 0.3em 0.1em 0.3em;
}
<table id="tableID">
<thead>
<tr>
<th>Column heading 1</th>
<th>Column heading 2</th>
<th>Column heading 3</th>
<th>Column heading 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>43</td>
<td>23</td>
<td>89</td>
<td>5</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>0</td>
<td>98</td>
</tr>
<tr>
<td>10</td>
<td>32</td>
<td>7</td>
<td>2</td>
</tr>
</tbody>
</table>
JS Fiddle proof-of-concept.
A revised approach, in response to the comment (below):
You're missing a semicolon. Also, don't make functions within a loop.
This revision binds a (single) named function as the click event-handler of the multiple <td> elements, and avoids the unnecessary overhead of creating multiple anonymous functions within a loop (which is poor practice due to repetition and the impact on performance, due to memory usage):
function logText() {
// 'this' is automatically passed to the named
// function via the use of addEventListener()
// (later):
console.log(this.textContent);
}
// using a CSS Selector, with document.querySelectorAll()
// to get a NodeList of <td> elements within the #tableID element:
var cells = document.querySelectorAll('#tableID td');
// iterating over the array-like NodeList, using
// Array.prototype.forEach() and Function.prototype.call():
Array.prototype.forEach.call(cells, function(td) {
// the first argument of the anonymous function (here: 'td')
// is the element of the array over which we're iterating.
// adding an event-handler (the function logText) to handle
// the click events on the <td> elements:
td.addEventListener('click', logText);
});
function logText() {
console.log(this.textContent);
}
var cells = document.querySelectorAll('#tableID td');
Array.prototype.forEach.call(cells, function(td) {
td.addEventListener('click', logText);
});
th,
td {
border: 1px solid #000;
padding: 0.2em 0.3em 0.1em 0.3em;
}
<table id="tableID">
<thead>
<tr>
<th>Column heading 1</th>
<th>Column heading 2</th>
<th>Column heading 3</th>
<th>Column heading 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>43</td>
<td>23</td>
<td>89</td>
<td>5</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>0</td>
<td>98</td>
</tr>
<tr>
<td>10</td>
<td>32</td>
<td>7</td>
<td>2</td>
</tr>
</tbody>
</table>
JS Fiddle proof-of-concept.
References:
Array.prototype.forEach().
document.getElementById().
document.getElementsByTagName().
document.querySelectorAll().
EventTarget.addEventListener().
Function.prototype.call().

This is my solution
var cells = Array.prototype.slice.call(document.getElementById("tableI").getElementsByTagName("td"));
for(var i in cells){
console.log("My contents is \"" + cells[i].innerHTML + "\"");
}

You can use:
<td onclick='javascript:someFunc(this);'></td>
With passing this you can access the DOM object via your function parameters.

I gave the table an id so I could find it. On onload (when the page is loaded by the browser), I set onclick event handlers to all rows of the table. Those handlers alert the content of the first cell.
<!DOCTYPE html>
<html>
<head>
<script>
var p = {
onload: function() {
var rows = document.getElementById("mytable").rows;
for(var i = 0, ceiling = rows.length; i < ceiling; i++) {
rows[i].onclick = function() {
alert(this.cells[0].innerHTML);
}
}
}
};
</script>
</head>
<body onload="p.onload()">
<table id="mytable">
<tr>
<td>0</td>
<td>row 1 cell 2</td>
</tr>
<tr>
<td>1</td>
<td>row 2 cell 2</td>
</tr>
</table>
</body>
</html>

.......................
<head>
<title>Search students by courses/professors</title>
<script type="text/javascript">
function ChangeColor(tableRow, highLight)
{
if (highLight){
tableRow.style.backgroundColor = '00CCCC';
}
else{
tableRow.style.backgroundColor = 'white';
}
}
function DoNav(theUrl)
{
document.location.href = theUrl;
}
</script>
</head>
<body>
<table id = "c" width="180" border="1" cellpadding="0" cellspacing="0">
<% for (Course cs : courses){ %>
<tr onmouseover="ChangeColor(this, true);"
onmouseout="ChangeColor(this, false);"
onclick="DoNav('http://localhost:8080/Mydata/ComplexSearch/FoundS.jsp?courseId=<%=cs.getCourseId()%>');">
<td name = "title" align = "center"><%= cs.getTitle() %></td>
</tr>
<%}%>
........................
</body>
I wrote the HTML table in JSP.
Course is is a type. For example Course cs, cs= object of type Course which had 2 attributes: id, title.
courses is an ArrayList of Course objects.
The HTML table displays all the courses titles in each cell. So the table has 1 column only:
Course1
Course2
Course3
......
Taking aside:
onclick="DoNav('http://localhost:8080/Mydata/ComplexSearch/FoundS.jsp?courseId=<%=cs.getCourseId()%>');"
This means that after user selects a table cell, for example "Course2", the title of the course- "Course2" will travel to the page where the URL is directing the user: http://localhost:8080/Mydata/ComplexSearch/FoundS.jsp . "Course2" will arrive in FoundS.jsp page. The identifier of "Course2" is courseId. To declare the variable courseId, in which CourseX will be kept, you put a "?" after the URL and next to it the identifier.
It works.

Related

Group column with the same subheader name in datatable using Javascript/jQuery

I have a table like this
In which I have different city where we have demand-supply of different products.
Now what I want as here demand is different for all the products However supply is the same on all of three product, so I want that table looks like in this manner.
What I want to do is I want only to show the supply column once in the last of the table. This has to be done dynamically as in the future we have multiple products
Can anyone help me with this?
What the code below does is:
Identify the positions of the "Supply"'s and store them in ind array, in this case will be [3, 5, 7]
Loops through ind except for the last element 7(as one "Supply" will be left) and hide all td's; $("td:nth-child("3"), $("td:nth-child("5")
The "Demand"s that precede each of these elements will be assigned two spaces.
let ind = [];
$("td:contains('Supply')").each(function (index) {
ind.push($(this).index() + 1);
});
$(".hide").on("click", function () {
for (let i = 0; i < ind.length - 1; i++) {
let el = $("td:nth-child(" + ind[i] + ")");
el.prev().attr("colspan", "2");
el.hide();
}
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<th>City</th>
<th colspan="2">Product 1</th>
<th colspan="2">Product 2</th>
<th colspan="2">Product 3</th>
</tr>
<tr>
<td></td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
</tr>
<tr>
<td>City 1</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 2</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 3</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 4</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
</table>
<button class="hide">Hide</button>

innerHTML to Attribute value Plain JavaScript

Here is my html
<table><thead>
<tr>
<th>Green</th>
<th>Orange</th>
</tr>
</thead>
<tbody>
<tr>
<td>First Stage A</td>
<td>First Stage B</td>
</tr>
<tr>
<td>Second Stage A</td>
<td>Second Stage B</td>
</tr>
</tbody></table>
Expected output
<table><thead>
<tr>
<th>Green</th>
<th>Orange</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Green">First Stage A</td>
<td data-label="Orange">First Stage B</td>
</tr>
<tr>
<td data-label="Green">Second Stage A</td>
<td data-label="Orange">Second Stage B</td>
</tr>
</tbody></table>
Here is the script
var _th = document.querySelectorAll("table th")[0];
var _th_value = _th.innerHTML;
var _td = document.querySelectorAll("table td")[0];
_td.setAttribute("basevalue", _th_value);
How could this to be done through plain JavaScript loop. I tried to figure this out for several hours by my existing JavaScript knowledge. But I couldn’t. Could someone please take a look and give me a hint? Advance thanks.
Step 1: You can first create a mapped array that contains the color values you can collect from the table thead th selector. You need to first convert a HTMLCollection to an array using ES6 Array.prototype.from, and then perform the mapping using Array.prototype.map:
const table = document.querySelector('table');
const colors = Array.from(table.querySelectorAll('thead th')).map(th => th.innerText);
p/s: The reason why innerText is used is so that we don't include any HTML tags, even though in your example innerHTML works just as fine. This is just a personal preference.
Step 2: Then, you simply iterate through all the table tbody tr elements. In each iteration you then iterate through all the td elements you can find, and with their index, use dataset to assign the corresponding color by index:
table.querySelectorAll('tbody tr').forEach(tr => {
tr.querySelectorAll('td').forEach((td, i) => {
td.dataset.color = colors[i];
});
});
See proof-of-concept below, where the cells are colored based on the data-color attribute for ease of visualisation (you can also inspect the DOM to see the correct HTML5 data- attributes are added):
const table = document.querySelector('table');
// Collect colors into an array
const colors = Array.from(table.querySelectorAll('thead th')).map(th => th.innerText);
// Iterate through all `<tr>` elements in `<tbody>
table.querySelectorAll('tbody tr').forEach(tr => {
// Iterate through all `<td>` in a particular row
tr.querySelectorAll('td').forEach((td, i) => {
// Assign color to HTML5 data- attribute
td.dataset.color = colors[i];
});
});
tbody td[data-color="Green"] {
background-color: green;
}
tbody td[data-color="Orange"] {
background-color: orange;
}
<table>
<thead>
<tr>
<th>Green</th>
<th>Orange</th>
</tr>
</thead>
<tbody>
<tr>
<td>First Stage A</td>
<td>First Stage B</td>
</tr>
<tr>
<td>Second Stage A</td>
<td>Second Stage B</td>
</tr>
</tbody>
</table>
var tables = document.getElementsByTagName('table');
for (let table of tables) {
var thead = table.children[0];
var tbody = table.children[1];
var index = 0;
for (let th of thead.children[0].cells) {
var color = th.innerHTML;
for (let tr of tbody.children) {
tr.children[index].setAttribute('data-label', color);
}
index++;
}
}
I had to handle the index outside the for loop because the children elements aren't simple arrays but HTMLCollections, and have different way to iterate over them.
edit: Added loop to iterate over all the tables in the page

How to modify a HTML <td> (without any unique properties) element using Javascript

I'm trying to modify a element using JS however this element does not have any unique properties like ID. Also the table in which this element resides does not have a unique class. Also, the HTML page has multiple tables and td elements.
For example:
Existing HTML :
<table border="1">
<tbody>
<tr>
<td>Id</td>
<td>Name</td>
</tr>
<tr>
<td>12334567</td>
<td>BirthName</td>
</tr>
</tbody>
</table>
I'm trying to modify the cell which contains the value "BirthName" to "BirthName (Sidharth)"
Something Like this:
<table border="1">
<tbody>
<tr>
<td>Id</td>
<td>Name</td>
</tr>
<tr>
<td>12334567</td>
<td>BirthName (Sidharth)</td>
</tr>
</tbody>
</table>
You can find all having BirthName by using bellow colde
const allTds = document.querySelectorAll('td')
// Find the td element that contains the text "BirthName"
const birthDateTd = Array.from(allTds).filter(td=>td.textContent==='BirthName')
After that you can target that <td> as you want.
You can do checking the text for all td and change where matches birthname
let element = document.querySelectorAll('td');
for(let i = 0; i<element.length; i++){
if(element[i].innerText == 'BirthName'){
element[i].innerText += '(Sidharth)';
}
}
If the text is unique then you can use Xpath as shown below and change it.
var td = document.evaluate("//td[contains(text(), 'BirthName')]", document, null, XPathResult.ANY_TYPE, null );
var thisTd = td.iterateNext();
thisTd.innerHTML = "BirthName (Sidharth)";
<table border="1">
<tbody>
<tr>
<td>Id</td>
<td>Name</td>
</tr>
<tr>
<td>12334567</td>
<td>BirthName</td>
</tr>
</tbody>
</table>

function getelementbyid not outputting to correct place

I am making a form to add players into an event.
The form searches a db of players with search criteria specified by the user and then lists all matching players with an add button next to them.
I also have a table with all the table headers done and then a
<div id="PlayerAdded">
tag before the end of the table.
I have written a function to output the data for the next row to the table when a players "Add" button is clicked. My function says:
function add(){
document.getElementById("PlayerAdded").innerHTML += "<tr><td>success</td></tr>";
}
I expected this to add a row, but instead it adds just the word "success" above the table (Perhaps I was a little optimistic when I used the word success as my test string lol).
Can someone please tell me why it is not adding the code inside the div "PlayerAdded"?
If it helps, here is some of the HTML:
<table border='1px'>
<tr><th colspan='6'> <?php echo ($eName . " - " . $vn); ?></th></tr>
<tr><th>Player ID</th>
<th>Player Name</th>
<th>Place</th>
<th>Points</th>
<th>Cash</th>
<th>Ticket?</th></tr>
<div id="PlayerAdded"> </div>
<tr><td colspan='3'>Search <input type='text' id='newsearch'></input>
</table>
There were a couple of problems with your existing HTML - which therefore broke your DOM when the browser attempted to assemble things.
a <div> element – in a <table> – must be contained within either a <th> or <td> element; no other element is a valid child of a <tr> element, and the only valid children of a <table> element are <thead>, <tfoot>, <tbody> and <tr> elements.
neither your last <tr>, or its child <td>, element were closed – the browser will automatically close these elements when it encounters another <td> (since neither a <td>, nor a <tr>, can be directly nested within another <td>).
That said, I'd correct your HTML to the following:
<table>
<tbody>
<tr>
<th colspan='6'>« php response »</th>
</tr>
<tr>
<th>Player ID</th>
<th>Player Name</th>
<th>Place</th>
<th>Points</th>
<th>Cash</th>
<th>Ticket?</th>
</tr>
<tr>
<td colspan='3'>Search
<input type='text' id='newsearch' />
</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<button id="addNewRow">Add a new row</button>
And your JavaScript to the following:
function addNewRow() {
// creating the relevant elements to be added:
var row = document.createElement('tr'),
td = document.createElement('td');
// setting the text of the created-<td> element:
td.textContent = 'Success';
// setting the colSpan property (the colspan attribute):
td.colSpan = '6';
// adding a class-name to the created-<td>, to make it
// visually obvious which are the newly-added <td>
// elements:
td.classList.add('addedRow');
// appending the created-<td> to the created-<tr>:
row.appendChild(td);
// finding the last <tr> of the table, using
// document.querySelector() which will match
// only the first element that matches the
// supplied CSS selector (or null, if no
// element exists that matches):
var lastRow = document.querySelector('table tr:last-child');
// inserting the created-<tr> (and its descendant
// elements parentNode of the lastRow node before
// the lastRow node):
lastRow.parentNode.insertBefore(row, lastRow);
}
// using unobtrusive JavaScript to add the 'click'
// event-listener to the <button> element with the
// id of 'addNewRow':
document.getElementById('addNewRow').addEventListener('click', addNewRow);
function addNewRow() {
var row = document.createElement('tr'),
td = document.createElement('td');
td.textContent = 'Success';
td.colSpan = '6';
td.classList.add('addedRow');
row.appendChild(td);
var lastRow = document.querySelector('table tr:last-child');
lastRow.parentNode.insertBefore(row, lastRow);
}
document.getElementById('addNewRow').addEventListener('click', addNewRow);
table,
td,
th {
border: 1px solid #000;
min-height: 2em;
}
td.addedRow {
font-weight: bold;
text-align: center;
border-color: limegreen;
}
<table>
<tbody>
<tr>
<th colspan='6'>« php response »</th>
</tr>
<tr>
<th>Player ID</th>
<th>Player Name</th>
<th>Place</th>
<th>Points</th>
<th>Cash</th>
<th>Ticket?</th>
</tr>
<tr>
<td colspan='3'>Search
<input type='text' id='newsearch' />
</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<button id="addNewRow">Add a new row</button>
External JS Fiddle demo, for experimentation or development.
References:
document.createElement().
document.getElementById().
document.querySelector().
Element.classList.
EventTarget.addEventListener().
Node.appendChild().
Node.insertBefore().
Try doing as user #Barmar said:
<script type="text/javascript">
function add(){
var _tr = document.createElement("tr");
var _textNode = document.createTextNode("Success");
_tr.appendChild(_textNode);
var _child = document.getElementById("botTr");
var parentDiv = _child.parentNode;
parentDiv.insertBefore(_tr, botTr);
}
</script>
And then:
<table border='1px'>
<tr><th colspan='6'> <?php echo ($eName . " - " . $vn); ?> </th></tr>
<tr id="topTr"><th>Player ID</th>
<th>Player Name</th>
<th>Place</th>
<th>Points</th>
<th>Cash</th>
<th>Ticket?</th>
</tr>
<tr id="botTr"><td colspan='3'>Search <input type='text' id='newsearch' />
</table>
<input type="button" name="hitme" id="hitme" value="hitme" onclick="add();" />

jQuery: How to re-count and re-name elements

I have a list of table rows and these tr's have numbered classes for some reason (leg-1, leg-2 etc). It is already possible to delete a single tr from within this context.
After deleting a tr I need to rename the remaining tr's.
Example:
I have
<tr class="leg-1"></tr>
<tr class="leg-2"></tr>
<tr class="leg-3"></tr>
Now I delete leg-2. Remaining are:
<tr class="leg-1"></tr>
<tr class="leg-3"></tr>
Now I want to rename the remaining tr's, so that it's back to leg-1 and leg-2.
How can this be done??
Thx for any help!
EDIT:
I forgot to mention that it can have more than one tr with class "leg-1", "leg-2" ... So the right starting example would be
<tr class="leg-1"></tr>
<tr class="leg-1"></tr>
<tr class="leg-2"></tr>
<tr class="leg-3"></tr>
<tr class="leg-3"></tr>
Now when I delete leg-2 , both of the tr's with class="leg-3" have to be renamed to be class="leg-2". ..
Sorry I didn't mention this earlier!!
SEE IT IN ACTION
http://jsfiddle.net/Lynkb22n/2/
I'd suggest, at its most straightforward:
$('tr').each(function(i) {
// looking for a class-name that starts with (follows a
// word-boundary: \b) leg- followed by one or more numbers (\d+)
// followed by another word-boundary:
var matchedClass = this.className.match(/\bleg-\d+\b/);
// if a match exists:
if (matchedClass) {
// set the node's className to the same className after replacing
// the found leg-X class name with the string of 'leg-' plus the
// index of the current element in the collection plus one:
this.className = this.className.replace(matchedClass[0], 'leg-' + (i + 1));
}
});
$('tr').each(function(i) {
var matchedClass = this.className.match(/\bleg-\d+\b/);
// if a match exists:
if (matchedClass) {
this.className = this.className.replace(matchedClass[0], 'leg-' + (i + 1));
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr class="leg-2323523">
<td>1</td>
</tr>
<tr class="leg-2323523">
<td>2</td>
</tr>
<tr class="leg-2323523">
<td>3</td>
</tr>
<tr class="leg-2323523">
<td>4</td>
</tr>
</tbody>
</table>
Using an id is somewhat easier, since we don't need to preserve pre-existing concurrent ids, as we do with classes:
// selects all <tr> elements, sets their `id` property
// using the anonymous function available within prop():
$('tr').prop('id', function (i) {
// i: the index amongst the collection of <tr> elements:
return 'leg-' + (i+1);
});
$('tr').prop('id', function (i) {
return 'leg-' + (i+1);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
<tr>
<td>4</td>
</tr>
</tbody>
</table>
If the index/row-number is simply to be available to JavaScript, then you could just as easily use the native rowIndex property available to all HTMLTableRowElements:
// selects <tr> elements, binds the 'mouseenter' event-handler:
$('tr').on('mouseenter', function() {
// logs the HTMLTableRowElement rowIndex property
// to the console:
console.log(this.rowIndex);
});
$('tr').on('mouseenter', function() {
console.log(this.rowIndex);
});
td {
border: 1px solid #000;
width: 4em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
<tr>
<td>4</td>
</tr>
</tbody>
</table>
References:
JavaScript:
HTMLTableRowElement.
JavaScript Regular Expression Guide.
String.prototype.match().
String.prototype.replace().
jQuery:
each().
prop().
Updated
Based on your comment below and your updated question, here is an updated solution.
var removed = $(".leg-2"),
siblings = removed.nextAll(), // affect only next siblings to removed element
pos = ""; // store current number after "leg-"
removed.remove(); // remove element
siblings.each(function (k) {
$(this).removeClass(function (i, key) {
pos = key.split("-")[1]; // update number after "leg-"
return (key.match(/\bleg-\S+/g) || []).join(' ');
}).addClass("leg-" + (pos - 1)); // add "leg-" plus new position
});
See it working here.
You can use .removeClass() with .match() to remove class starts with leg and then add class leg plus tr's index using .addClass().
See it working here.
$("tr").each(function (k) {
k++;
$(this).removeClass(function (i, key) {
return (key.match(/\bleg-\S+/g) || []).join(' ');
}).addClass("leg-" + k);
});
Try this it will re-name the class:
$(document).ready(function(){
$("#click").click(function(){
reorder();
});
});
function reorder(){
$('#myTable > tbody > tr').each(function(index) {
console.log($(this).attr('class','leg-'+(index+1)));//avaoid starting fron 0
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<tr class="leg-1"><td>a1</td></tr>
<tr class="leg-2"><td>a2</td></tr>
<tr class="leg-3"><td>a3</td></tr>
<tr class="leg-7"><td>a4</td></tr><!--after click on button class will become class="leg-4" -->
<tr class="leg-8"><td>a5</td></tr><!--after click on button class will become class="leg-5" -->
</table>
<button id="click">CliCk</button>

Categories