Reputation: 5251
I am adding click handler into one of table elements. I confirmed it on inspect -> console that this is the returns the value that I need, the address value.
document.getElementById('donut-attributes').parentNode.childNodes[10].childNodes[1].childNodes[30].innerText
//returns 123 Some Address on console log
This is the complete script on main page:
<script>
window.onload = function(){
var donutContainer = document.getElementById("donut-attributes");
donutContainer.addEventListener('click', function(e){
alert(e.target.parentNode);
address = e.target.parentNode.childNodes[10].childNodes[1].childNodes[30].innerText;
alert("donut container after");
});
}
</script>
I set up several alert()
to make sure everything works. When it comes down to alert(e.target.parentNode)
, it shows [object HTMLTableRowElement]
. However, when it comes down to alert(e.target.parentNode.childNodes[10]);
, it returns undefined
.
How can I fix the click handler so when I click any table element, I would get the address value stored into address
? Why does it show the address on console log and it shows undefined
when I used it with clickhandler?
EDIT: the table html (index.html.erb)
looks something like this:
<table border=1 class="table table-condensed donut-attributes">
<tbody class="table-hover">
<tr>
<td rowspan=5>
Some_image
</td>
<tr>
<td class="center" style="vertical-align: middle">Some_name</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">Some_phone</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">Some_rating</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle" id="address" >Some_address</td>
</tr>
<tr>
<td rowspan=5>
Some_image2
</td>
<tr>
<td class="center" style="vertical-align: middle">Some_name2</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">Some_phone2</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">Some_rating2</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle" id="address" >Some_address2</td>
</tr>
</tr>
</tbody>
How can I hover on any element on a table row, click it, and get the corresponding address? (i.e. if I hover and click on the second row, on any column in the second row, I need it to return some_address2)
Upvotes: 0
Views: 975
Reputation: 44043
UPDATE
Updated so now it does exactly what OP needed, so if a <tbody>
is clicked, we will get the text of the td.address
that resides within it. In the source is a "lynchpin" comment added to alter the extractData()
function so that it'll collect the text of whatever is clicked. Details are commented in the Snippet's code.
SNIPPET
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<title>00A00</title>
<style>
table.X {
padding: 0;
box-shadow: 0 1px 9px 1px #ccc;
border-radius: 6px;
margin: 20px auto;
}
.X th {
color: #FFF;
background: #FA768E;
padding: 10px;
text-align: center;
vertical-align: middle;
}
.X tr:nth-child(odd) {
background-color: #FA768E;
color: #FFF;
}
.X tr:nth-child(even) {
background-color: #D3E9FF;
color: #F9F;
}
.X td {
border-style: solid;
border-width: 1px;
border-color: #FA768E;
padding: 5px;
text-align: left;
vertical-align: top;
}
.X thead th:first-child {
border-top-left-radius: 6px;
}
.X thead th:last-child {
border-top-right-radius: 6px;
}
.X tbody tr:first-child td:first-child {
border-top-left-radius: 6px;
}
.X tbody tr:first-child td:last-child {
border-top-right-radius: 6px;
}
.X thead+tbody tr:first-child td:first-child {
border-top-left-radius: 0;
}
.X thead+tbody tr:first-child td:last-child {
border-top-right-radius: 0;
}
.X tbody tr:last-child td:first-child {
border-bottom-left-radius: 6px;
}
.X tbody tr:last-child td:last-child {
border-bottom-right-radius: 6px;
}
.X tbody td.center.center {
text-align: center;
padding: 10px;
vertical-align: middle;
}
.X tbody a {
color: #121;
}
.a {
background: #FEDAE0;
}
.rating {
font-size: 1.5rem;
}
.col2 {
color: #Fed;
background: #123;
}
.X tr:nth-child(even) td.col2 {
background: #Edf;
color: #325;
}
</style>
</head>
<body>
<table id="toons" class="table table-condensed X">
<tbody class="table-hover" data-lvl='1'>
<tr>
<td rowspan='5' class='col1'>
<img src='http://iconshow.me/media/images/ui/app-ui-icon/png/128/donut.png' class: 'thumbnail' style='margin-bottom:50px;'>
<img src='http://icons.veryicon.com/png/Movie%20%26%20TV/Simpsons%204/Homer%20Simpson%2001%20Donut.png' class='thumbnail' style='width:200px;height:200px;'>
</td>
</tr>
<tr>
<td class="link center col1"><a href='https://www.facebook.com/HurtsDonutCompany'>Hurt's Donut Company</a>
</td>
</tr>
<tr>
<td class="phone center col1">417.300.6106</td>
</tr>
<tr>
<td class="rating center col1">⭐⭐⭐⭐⭐</td>
</tr>
<tr>
<td class="address center col1">320 Park Central W.
<br>Springfield, Missouri, USA</td>
</tr>
</tbody>
<tbody class="table-hover">
<tr>
<td rowspan='5' class='col2'>
<img src='http://imgh.us/space-donut.gif' class: 'thumbnail' style='margin-bottom:50px;width:200px;'>
<img src='http://imgh.us/gir_zim.gif' class='thumbnail' style='width:200px;height:200px;'>
</td>
</tr>
<tr>
<td class="link center col2"><a href='https://training.gov.au/Training/Details/FDFRB3014A'>Fried Yeast Products</a>
</td>
</tr>
<tr>
<td class="phone center col2">꩸၏🜐🝳</td>
</tr>
<tr>
<td class="rating center col2">🌎🌎🌎🌎🌎</td>
</tr>
<tr>
<td class="address center col2">WarpGate U812
<br>Horsehead Nebula, Irk</td>
</tr>
</tbody>
</table>
<script>
// Collect and reference every <tbody>
var T = document.querySelectorAll('tbody');
// For each <tbody>...
[].forEach.call(T, function(t, idx) {
/* When any part of the <tbody> is clicked...
|| ...function extractData() is called
*/
T[idx].addEventListener('click', extractData, false);
});
/* extractData() will pass an event object...
|| ...and using it's properties to find...
|| ...event.target (the node that was clicked)...
|| ...Next we store the event.target in a var...
|| ...and check to see if it has the class .address...
|| ...if it doesn't, we will find the <tbody> ...
|| ...that it belongs to. From there we'll find...
|| ...td.address and get it's text content...
|| ...Otherwise if we had clicked the td.address...
|| ...we'll have the text already.
*/
function extractData(event) {
if (event.target !== event.currentTarget) {
var dataSource = event.target;
//* Remove a '/' to get the exact text of each <td>
if (!dataSource.classList.contains('address')) {
var grandma = dataSource.closest('tbody');
console.log(grandma.querySelector('.address').textContent);
} else //*/
console.log(dataSource.textContent);
}
}
</script>
</body>
</html>
In the markup (HTML), each "subject" is in it's own <tbody>
this helps us to not only to organize the data better, it also facilitates DOM transversal as well. Having multiple <tbody>
is completely valid as well.
Upvotes: 1
Reputation: 350776
Duplicate values for the id
attribute are not allowed in HTML, so you should remove that attribute from the td
with id="address"
, since it gets repeated.
To identify the "last" row in the group, you could reason that this row has a row index (zero-based) of 4, plus a multiple of 5. Or in other words, it is 4 modulo 5. Once you know the row index of the row that is being clicked in, it is not so hard to find the next row that has such an index:
window.addEventListener('DOMContentLoaded', function(){
var donutContainer = document.getElementById("donut-attributes");
donutContainer.addEventListener('click', function(e){
// Get the clicked element
var el = e.target;
// Find row that contains (or is) the clicked element
while (el.tagName !== 'TR') {
if (el === this) return; // give up
el = el.parentNode;
}
// Get last row within group of rows
el = this.rows[el.rowIndex - el.rowIndex % 5 + 4];
// Get its text
address = el.cells[0].textContent;
alert(address);
});
});
table, td {border: 1px solid}
<table id="donut-attributes" class="table table-condensed">
<tbody class="table-hover">
<tr>
<td rowspan=5>[image 1]</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">name1</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">phone1</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">rating1</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">address1</td>
</tr>
<tr>
<td rowspan=5>[image 2]</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">name2</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">phone2</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">rating2</td>
</tr>
<tr>
<td class="center" style="vertical-align: middle">address2</td>
</tr>
</table>
Note that if you have a special header row in your table, or other rows that do not follow the multiple-of-five pattern, the formula has to be adapted accordingly.
Upvotes: 1