I have a table with 10 columns and I want to add one or more event listeners to columns from 5th to 8th by using specifically addEventListener
statement (so please no inline events like element.onclick
).
The table is dynamic, in fact I don't know at programming time how many records the table will have at runtime because it will be populated by data only at that moment.
I already know how to "aim" to a table or to a table row or to a specified table cell to add event listeners to them but unfortunately I don't understand how to add them to certain columns or to a range of columns at once ("at once" means a for loop that loops through every row to get the desired cell of each).
Edit
The table is just a normal table like the following example and it is populated by loading data records from csv file or by adding new records by a form placed into the tfoot of the table itself. Also it is possible to edit the data into the table itself thanks to the contenteditable
attribute added (or removed) dynamically by js when needed.
If I want to add an event listener to a row I first get the row object then I add the eventlistener to it once: all td elements will be affected as I need thanks to event propagation/delegation. Is that possible to do the same with columns?
myRow.addEventListener(input, myfunc, false);
In other words is it possible to do something like:
myCol5.addEventListener(input, myfunc, false);
myCol6.addEventListener(mouseover, myfunc, false);
myCol7.addEventListener(click, myfunc, false);
myCol8.addEventListener(input, myfunc, false);
table, td, th
{
border: 1px solid black;
border-collapse: collapse;
}
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro ercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
</tr>
</table>
I have a table with 10 columns and I want to add one or more event listeners to columns from 5th to 8th by using specifically addEventListener
statement (so please no inline events like element.onclick
).
The table is dynamic, in fact I don't know at programming time how many records the table will have at runtime because it will be populated by data only at that moment.
I already know how to "aim" to a table or to a table row or to a specified table cell to add event listeners to them but unfortunately I don't understand how to add them to certain columns or to a range of columns at once ("at once" means a for loop that loops through every row to get the desired cell of each).
Edit
The table is just a normal table like the following example and it is populated by loading data records from csv file or by adding new records by a form placed into the tfoot of the table itself. Also it is possible to edit the data into the table itself thanks to the contenteditable
attribute added (or removed) dynamically by js when needed.
If I want to add an event listener to a row I first get the row object then I add the eventlistener to it once: all td elements will be affected as I need thanks to event propagation/delegation. Is that possible to do the same with columns?
myRow.addEventListener(input, myfunc, false);
In other words is it possible to do something like:
myCol5.addEventListener(input, myfunc, false);
myCol6.addEventListener(mouseover, myfunc, false);
myCol7.addEventListener(click, myfunc, false);
myCol8.addEventListener(input, myfunc, false);
table, td, th
{
border: 1px solid black;
border-collapse: collapse;
}
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro ercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
</tr>
</table>
Share
edited Feb 5, 2017 at 13:10
Brian Tompsett - 汤莱恩
5,89372 gold badges61 silver badges133 bronze badges
asked Feb 2, 2017 at 2:01
willy wonkawilly wonka
1,6961 gold badge22 silver badges32 bronze badges
10
- 3 Possible duplicate of add event listener on elements created dynamically – castletheperson Commented Feb 2, 2017 at 2:05
- 1 You should add some code. And what do you mean by dynamic? Does it change without reloading the page? Need to see the structure of your table (HTML)... also, have you considered using jQuery? It will make a task like this much easier. – Christopher Reid Commented Feb 2, 2017 at 2:09
- 1 @4castle I don't think that's OP's issue. The main question here appears to be identifying the column – Phil Commented Feb 2, 2017 at 2:11
- 1 add listener to row and figure out from classes or index of cells which column it is. Provide a minimal reproducible example – charlietfl Commented Feb 2, 2017 at 2:17
-
2
Trying to do lookups by
nth
positiontd
inside atr
is going to be troublesome given that you canrowspan
on atd
. I would STRONGLY suggest adding a class attribute (ie.class="myColumn"
) to thetd
's you're trying to target, and using that for your "aim"ing – haxxxton Commented Feb 2, 2017 at 2:28
3 Answers
Reset to default 5With window.event.target.cellIndex
is possible to get the cell index (from 0 to n where n is the number of table columns - 1) of a clicked cell that is the column index.
With window.event.target.parentNode.rowIndex
is possible to get the row index (from 0 to n where n is the number of table rows - 1) of a clicked cell that is the row/record index.
Example:
var col = window.event.target.cellIndex;
var row = window.event.target.parentNode.rowIndex;
Working example:
document.getElementById('myTbl').addEventListener('click', function(){myFunction(event)}, false);
function myFunction()
{
var col = window.event.target.cellIndex;
var row = window.event.target.parentNode.rowIndex;
alert('Col index is: ' + col + '\nRow index is: ' + row);
// At this point it is easy to do something like:
// if(col > 5 && col < 8)
{
//Execute this stuff
}
}
table, td {
border: 1px solid black;
}
<p>Click on each td element to alert its position in the table row.</p>
<table id="myTbl">
<tr>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
</tr>
<tr>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
</tr>
<tr>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
</tr>
<tr>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
<td>Click to show cellIndex</td>
</tr>
</table>
Using the idea from user haxxton about adding classes, you can use event delegation to listen for events on the table cells that match your column requirements.
// sort of like jQuery's .closest
const findClosest = (element, selector, context) => {
context = context || element.document || element.ownerDocument
while (element !== context) {
if (element.matches(selector)) {
return element
}
element = element.parentNode
}
return null
}
document.querySelector('table > tbody').addEventListener('click', function(e) {
const td = findClosest(e.target, 'td.handleClick', this)
if (td) {
console.log('Got a click on', td)
}
}, false)
<!-- adding classes for columns 1 and 3 -->
<table border="1" cellpadding="10">
<tbody>
<tr>
<td class="handleClick">
<span>ONE</span>
</td>
<td>TWO</td>
<td class="handleClick">THREE</td>
</tr>
<tr>
<td class="handleClick">ONE</td>
<td>TWO</td>
<td class="handleClick">THREE</td>
</tr>
</tbody>
</table>
See Element.matches
for more information on that method.
In some use cases you can use event delegation and then iterate over the TR's children to find the index of the column from there you could trigger a function specific to each column easily and as it's delegated to the table any dynamically created cells will have the event listener ready to go.
This will be fine for simple tables but may not behave if rowspans are involved - classes or attributes may be the better option for tables like that.
document.getElementById('myTable').addEventListener('click', function(e){
var elem = e.target;
var tr = closestTag(elem, "TR"); // Find which TR was clicked
var td = (elem.tagName == "TD") ? elem : closestTag(elem, "TD"); // Find the TD that was clicked
if(tr && td){
var column = TdIndex(e.target, tr); // Figure out which column was clicked
console.log("Column Clicked", column);
}
});
function closestTag(elem, tag){ // Moves up the DOM tree till it finds <tag> || <body>
while(elem.parentNode.tagName != tag && elem.tagName != 'BODY'){
elem = elem.parentNode;
}
return (elem.tagName == 'BODY') ? false : elem.parentNode;
}
function TdIndex(elem, tr){ // Returns the index of a TD contained in a TR
for(var i=0; i < tr.children.length; i++){
if(tr.children[i] == elem) return i;
}
return false;
}
<table id="myTable">
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro ercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
</tr>
</table>