Javascript stop TR click event on dropdown selecti

2019-07-31 01:25发布

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>

5条回答
祖国的老花朵
2楼-- · 2019-07-31 01:41

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>

查看更多
爷的心禁止访问
3楼-- · 2019-07-31 01:50

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

查看更多
贼婆χ
4楼-- · 2019-07-31 01:52

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");
   }
}
查看更多
forever°为你锁心
5楼-- · 2019-07-31 01:55

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;">
查看更多
淡お忘
6楼-- · 2019-07-31 01:56

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.

查看更多
登录 后发表回答