0

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)

21
  • 2
    childNodes includes whitespace text nodes, and comment nodes between elements in counting. Use .children Commented Jan 5, 2017 at 22:02
  • 4
    Duplicate id values are not allowed in HTML. Commented Jan 5, 2017 at 22:13
  • 1
    how do we know what you mean with image, name, when none of that is in your question? Can you edit your question and add the missing information? Commented Jan 5, 2017 at 22:16
  • 3
    div tags cannot be children of tr tags. Commented Jan 5, 2017 at 22:23
  • 1
    .childNodes[10].childNodes[1].childNodes[30] seems really bad design... Can't you add a class or name to select? And you can not have a div as child in a table's row. That is not valid HTML. Commented Jan 5, 2017 at 22:24

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

UPDATE

Updated so now it does exactly what OP needed, so if a <tbody> is clicked, we will get the text of the td.addressthat 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">&#11088;&#11088;&#11088;&#11088;&#11088;</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">&#43640;&#4175;&#128784;&#128883;</td> </tr> <tr> <td class="rating center col2">&#127758;&#127758;&#127758;&#127758;&#127758;</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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.