innerHTML to Attribute value Plain JavaScript - 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

Related

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>

Why does this shuffle function only work with 4+ items? JsFiddle included

I have the following code, which shuffles a set of items in the row of a table. However, the shuffle function only works when there are 4+ items:
var parent = $("#parent");
function shuffleRows(parent) {
var rows = parent.children().children(".shuffledtd1");
for (var i = rows.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = rows[i];
rows.eq(i - 1).after(rows[j]);
rows.eq(j - 1).after(temp);
}
}
shuffleRows(parent);
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<table>
<tbody id="parent">
<tr id="node2" class="shufflerow">
<td class="shuffledtd shuffledtd1">AA</td>
<td class="shuffledtd shuffledtd1">BB</td>
<!-- IF I DELETE THIS AND THE FOLLOWING ROW, THE PRIOR 2 ROWS NO LONGER SHUFFLE -->
<td class="shuffledtd shuffledtd1">CC</td>
<td class="shuffledtd shuffledtd1">DD</td>
</tr>
</tbody>
</table>
Full Code: http://jsfiddle.net/d8rkgx0z/
I think it has something to do with this portion of the code:
rows.eq(i - 1).after(rows[j]);
rows.eq(j - 1).after(temp);
but, unfortunately, my skill set simply isn't robust enough to isolate and correct the issue without hours of trial and error.
Thanks in advance for the help!
Instead of calling children twice, just pass in the direct parent of the cells. Also, shuffling the children is a lot easier using jQuery#sort:
var parent = $("#node2"); // parent should be the tr element not the tbody which is in fact a grandparent not a parent
function shuffleChildren(parent) {
parent.children() // get the children of the parent element
.sort(function() { return Math.random() - 0.5; }) // sort them randomly (shuffling)
.appendTo(parent); // add them back to parent so that the shuffling takes effect
}
shuffleChildren(parent);
Example:
var parent = $("#node2"); // parent should be the tr element not the tbody which is in fact a grandparent not a parent
function shuffleChildren(parent) {
parent.children() // get the children of the parent element
.sort(function() { return Math.random() - 0.5; }) // sort them randomly (shuffling)
.appendTo(parent); // add them back to parent so that the shuffling takes effect
}
shuffleChildren(parent);
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<table>
<tbody id="parent">
<tr id="node2" class="shufflerow">
<td class="shuffledtd shuffledtd1">AA</td>
<td class="shuffledtd shuffledtd1">BB</td>
<td class="shuffledtd shuffledtd1">CC</td>
<td class="shuffledtd shuffledtd1">DD</td>
</tr>
</tbody>
</table>
Note: If you want to do this to all rows, then just use jQuery#each:
$("#parent tr").each(function() { // get all tr inside #parent
shuffleChildren($(this)); // shuffle their children
});
BTW, what you're shuffling are cells not rows.
ibrahim mahrir's answer is the more elegant way to do what you're trying to do, but in the interest of helping you understand why your solution wasn't working I'm posting this as well.
The Problem:
The problem you were seeing is because when i = 0, when you do (i - 1) you get negative one, which is not a valid index in your table.
rows.eq(i - 1).after(rows[j]);
The way to make your solution work:
Below is how you could have solved that issue with your existing code:
function shuffleRows(parent) {
var rows = parent.children().children(".shuffledtd1");
// Changed to i >= 0.
for (var i = rows.length - 1; i >= 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = rows[i];
// Changed to just i, instead if i-1.
rows.eq(i).after(rows[j]);
rows.eq(j - 1).after(temp);
}
}
$('button').on('click', function() {
shuffleRows($("#parent"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody id="parent">
<tr id="node2" class="shufflerow">
<td class="shuffledtd shuffledtd1">AA</td>
<td class="shuffledtd shuffledtd1">BB</td>
<td class="shuffledtd shuffledtd1">CC</td>
</tr>
</tbody>
</table>
<button>Shuffle</button>
This snippet just made two small changes, which I noted in the code, to avoid the negative index problem you had.
Again, there are much more elegant ways to approach this task, but I always get a lot out of understand why something doesn't work, so I wanted you to have an explanation.
Your script can be simplified by great lengths, especially using proper selectors and a random sorter (Covered both cases of sorting td within a tr - or tr within a tbody:
const randomSorter = () => 0.5 - Math.random();
$('.shufflecells tr').each(function() {
$(this).html($('td', this).sort(randomSorter));
});
$('.shufflerows').each(function() {
$(this).html($('tr', this).sort(randomSorter));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<table>
<tbody class="shufflecells">
<tr>
<td>AA</td>
<td>BB</td>
<td>CC</td>
<td>DD</td>
</tr>
</tbody>
</table>
<table>
<tbody class="shufflecells">
<tr>
<td>AA</td>
<td>BB</td>
</tr>
</tbody>
</table>
<table>
<tbody class="shufflerows">
<tr>
<td>AA</td>
</tr>
<tr>
<td>BB</td>
</tr>
<tr>
<td>CC</td>
</tr>
<tr>
<td>DD</td>
</tr>
</tbody>
</table>

javascript - select nodes and all their child nodes inside tbody

I want to select all elements inside < tbody > and all their sub-elements so i can change a class using javascript.
For example, i want to change the class cl1 into cl2 in the following example
<table>
<thead>
....
</thead>
<tbody id="my-table">
<tr class="cl1 other-class">
<td>Some value</td>
<td class="cl1 other-class">Some value</td>
<td>Some value</td>
</tr>
<tr class="cl1 other-class">
<td class="cl1 other-class">Some value</td>
<td>Some value</td>
<td>
<a class="cl1 link" href="#">Some link</a>
</td>
</tr>
</tbody>
I want to use javascript for this, no jQuery
i managed to select all elements inside < tbody > like this :
document.getElementById("my-table").tBodies.item(0)
but i didn't know how to select each of their sub-elements or their sub-sub-elements.
for changing the class, i know i can use regular expressions to replace the class
Possible duplicate How to select all children of an element with javascript and change CSS property?
try (add an id to your tbody to make this work)
var descendants = document.getElementById('tbody').getElementsByTagName("*");
for(var i = 0; i < descendants.length; i++) {
descendants[i].classList.remove('cl1');
descendants[i].classList.add('cl2');
}
You said you managed to select <tbody> element, but you wanted to know how to select it's sub-elements or their sub-sub-elements. You do that with the children property which each element has. So this line gives you all children of <tbody> which are the <tr> (rows):
document.getElementById("my-table").tBodies.item(0).children;
Then if you get the children of each row, you get the cells. Example:
var tbody = document.getElementById("my-table").tBodies.item(0);
var rows = tbody.children;
var row1cells = rows[0].children;
var row2cells = rows[1].children;

Need to compare a certain cell in contiguous rows and find rows where the value of that cell changes

I have an html table generated dynamically from a database. Rows where a particular cell value is the same represents paired data and I want to separate those pairs with an empty row. The best way I can think of is to find where that value differs from the preceding value. Is this possible?
<table id="myTable">
<tr>
<th>Team #</th>
<th>Name</th>
<th>Age</th>
</tr>
<tbody>
<tr class="data-in-table">
<td class="id">12345</td>
<td>Tom</td>
<td>46</td>
<tr class="data-in-table">
<td class="id">12345</td>
<td>Dick</td>
<td>32</td>
<tr class="data-in-table">
<td class="id">34567</td>
<td>Harry</td>
<td>45</td>
<tr class="data-in-table">
<td class="id">76543</td>
<td>Will</td>
<td>45</td>
</tr>
<tr class="data-in-table">
<td class="id">76543</td>
<td>Sam</td>
<td>45</td>
</tr>
</tbody>
This is code I've seen comparing adjacent cells and tried to change for my needs:
$("#myTable").each(function () {
$(this).find('tr').each(function (index) {
var currentRow = $(this);
var nextRow = $(this).next('tr').length > 0 ? $(this).next('tr') : null;
if (index%2==0&&nextRow && currentRow(td[0].text() != nextRow(td[0].text()) {
$('#myTable tr:next').after('<tr><td></td><td></td><td></td></tr>');
}
});
});
I'd like it to look something like this:
Team # Name Age
12345 Tom 46
12345 Dick 32
34567 Harry 45
76543 Will 45
76543 Sam 45
As the database updates, team members will always be positioned adjacent to each other, but sometimes one teammate will appear before the second teammate and the table should reflect that.
I found that this works, through trial and error:
var last = ''
var rowCount = $('#myTable >tbody >tr').length;
for (var i=0;i<rowCount-1;i++) {
if (last != $('#myTable tr .id:eq('+i+')').html()) {
var lastRow = $('#myTable tr .id:eq('+i+')')
$(lastRow).parents('tr').before('<tr><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td></tr>')
}
var last = $('#myTable tr .id:eq('+i+')').html()
}
I don't know if there is a more efficient way than using a for.. statement to run through each row.

How to get html table td cell value by 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.

Categories