I want to capture what option has been selected from dropdown. Here the problem is when option is being clicked TR click event is called because select
doesn't have click event.
How can I stop TR click event when drop down is clicked?
<html>
<script>
function check1() {
alert("TR clicked");
}
function check2() {
alert("drop_down clicked");
}
</script>
<table border=1>
<tr onclick="check1();">
<td>My Options</td>
<td>
<select name="" id="drop_down" onchange="check2();">
<option value="A">A</option>
<option value="B">B</option>
</select>
</td>
</tr>
</table>
You need to capture click
event on <select>
and prevent its propagation:
function onSelectClick(ev) {
ev.stopPropagation();
}
<select onclick="onSelectClick">
or you can try to simply return false
for click
event for <select>
:
<select onclick="return false;">
You can just check what element triggered the click, and if it was the drop down, ignore the event:
function check1(e) {
if (typeof e == "undefined")
e = window.event;
if (e.srcElement.id != "drop_down") {
alert("TR clicked");
}
}
jsfiddle sample
If you want the JS to be more generic and not check for specific ID of elements, you can also change its logic to look for elements having a custom attribute defined:
function check1(e) {
if (typeof e == "undefined")
e = window.event;
if (e) {
var sourceElement = e.srcElement || e.target;
if (sourceElement) {
if (sourceElement.getAttribute("data-stop-propagation")) {
//element being clicked asked to ignore the event, abort
return;
}
}
}
alert("TR clicked");
}
To make it work with your code, change the HTML to this: (the value of the attribute doesn't matter)
<select name="" id="drop_down" onchange="check2();" data-stop-propagation="1">
updated fiddle
one more thing you can do is get event target,
function check1() {
if(this.event.target.nodeName!=='SELECT'){
alert("TR clicked");
}
}
to support in all browsers just capture event and pass it as param
<tr onclick=check1(event)>....</tr>
//in js
function check1(event) {
if(event.target.nodeName!=='SELECT'){
alert("TR clicked");
}
}
Use addEventListener()
instead of inline attribute eventHandlers. At the end of the eventListener()
, or at the end of callback, add e.stopPropagation()
so the event never bubbles thereby never reaching <tr>
.
<tr>
will need to be referenced as it is relative to another table component such as <table>
or <td>
. Although inline attribute events stick to anything (including a <tr>
tag), it will become detrimental to maintaining such a layout (as I suspect it is already occurring). This is why it has been strongly suggested that addEventListener()
be used instead of inline events.
In the following demo:
If <select>
is clicked the console logs its value.
If a <td>
is clicked then it logs a generic 'click'
It will not log both at click event
All modern browsers are supported
Details commented in demo
Demo
var table = document.querySelector('table');
function chk() {
var drop = document.getElementById('drop');
var val = drop.value
console.log(val);
}
function rowLog() {
console.log('Clicked');
}
table.addEventListener('click', function(e) {
/* if the clicked element (e.target) is NOT
|| the element registered to listen for
|| click event (table) then...
*/
if (e.target !== e.currentTarget) {
/* if clicked element's #id is drop
|| call function chk()
*/
if (e.target.id === 'drop') {
chk();
/* Stop the event from bubbling (thereby
|| event never reaches TR if #drop is clicked)
*/
e.stopPropagation();
}
/* TR is tightly integrated with TD so
|| target TD or spicify TBODY or TABLE
|| to reference TR.
|| Note e.stopPropagation() is not invoked
|| in this function so click event will
|| bubble to <tr>
*/
else if(e.target.tagName === 'TD') {
rowLog();
}
}
}, false);
<table border=1>
<tr>
<td>My Options</td>
<td>
<select name="" id="drop">
<option></option>
<option value="A">A</option>
<option value="B">B</option>
</select>
</td>
</tr>
</table>
I found this solution to work best for me:
<html>
<script>
function check1(event) {
// check if the event path contains the select element
// Not checking null values for simplicity
var preventFlag = event.path.filter(obj =>
obj.id.include('select')).length > 0
if(!preventFlag) {
// triggered only when preventFlag is false
alert("TR clicked");
}
}
function check2() {
alert("drop_down clicked");
}
</script>
<table border=1>
<tr onclick="check1(event);">
<td>My Options</td>
<td>
<select name="" id="drop_down" onchange="check2();">
<option value="A">A</option>
<option value="B">B</option>
</select>
</td>
</tr>
</table>
The good thing about this solution is that it works for all child elements inside the desired target element. For e.g, this logic works when a select element is clicked and it also works when any of the options inside the select element are clicked.
Downside: the path array needs to be looped through.