3

I have the following HTML-table:

<table>
  <tr>
    <td>
      Row 1
    </td>
    <td>
      <!-- Hidden JSF-button -->
      <button class="hide" />
    </td>
  </tr>
</table>

When I click on a tr, I trigger a click on the hidden button with JS:

$('table tr').on('click', function(e) {
  var $button = $(this).find('button');  
  console.log('trigger click on', $button);
  
  $button.trigger('click');
});

The click event propagates up, and will cause a never ending loop (can be seen here: http://codepen.io/anon/pen/kDxHy)

After some searching on Stack Overflow, it is clear that the solution is to call event.stopPropagation,
like this (can be seen here: http://codepen.io/anon/pen/BnlfA):

$('table tr').on('click', function(e) {
  var $button = $(this).find('button');
  
  // Prevent the event from bubbling up the DOM tree.
  $button
    .off('click')
    .on('click', function(e) {
      console.log('click');
      e.stopPropagation();
    
    return true;
  });
  
  console.log('trigger click on', $button);
  
  $button.trigger('click');
});

The solution above works. But it feels like a hack, and I don't like it.

Do I have to register a click handler on the on the $button just to call event.stopPropagation? Are there any better way(s) of preventing the click event from bubbling?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
nekman
  • 1,919
  • 2
  • 15
  • 26
  • why do you need to trigger click on that hidden button ? – magyar1984 Sep 23 '13 at 21:14
  • The button is actually a hidden JSF-button (http://www.mkyong.com/jsf2/jsf-2-button-and-commandbutton-example/). When a user clicks on a row in the table I trigger a click on the button, that calls the backing controller (server side) to set a value. – nekman Sep 23 '13 at 21:20
  • Oh sorry, I don't know MVC is involved. I'm not sure if this could help, but when you trigger event automaticaly, what's the event.target ? If it's button, that you could filter it and stopPropagation in tr event handler probably ? – magyar1984 Sep 23 '13 at 21:45

3 Answers3

2

A better overall solution would be not to trigger the click event at all but simply have a separate function that you can call and that encapsulates the event handler logic.

function doSomething(someArg) {
    //do something
}

$('button').click(function () {
    doSomething(/*pass whatever you want*/);
});

$('table tr').on('click', function () {
    doSomething(/*pass whatever you want*/);
});

Please note that doSomething doesn't have an event handler signature such as (e). That's generally a good practice to pass just what's needed to the function to do it's own work, not the whole event object. That will simplify the implementation of doSomething and decouple it completely from the event object.

EDIT:

Sorry, but I need to manually trigger the button click when the user clicks on a tr. Please see my comment to @magyar1984 question.

In this case you probably found the best solution already, which is to attach an event listener on the button and call stopPropagation. You could also look into getting all click event handlers by using the events data on the element, but beware that you would then be relying on jQuery internals so the code could break in future releases.

Have a look at this question to know how to retrieve the event handlers.

Pavel Chuchuva
  • 22,633
  • 10
  • 99
  • 115
plalx
  • 42,889
  • 6
  • 74
  • 90
  • Sorry, but I need to manually trigger the button click when the user clicks on a tr. Please see my comment to @magyar1984 question. – nekman Sep 23 '13 at 21:35
  • Thanks, yes I assume that the solution must be to manually prevent the event from bubbling. I made a plugin that could be used as a shortcut to prevent bubbling. http://nekman.se/prevent-jquery-event-from-bubbling/ – nekman Sep 26 '13 at 18:34
0

I was able to get it to only register the button click once by updating your codepen to the following:

var handleClick = function(e) {
  var $button = $(this).find('button');  
  console.log('trigger click on', $button);

  $button.trigger('click');
};
$('button.hide').on('click',function(e){
  e.stopPropagation();
});

$(function() {
    $('table tr')
    .on('click', handleClick);
});

But the general idea is to declare an onClick event on the button and stop the propagation there.

mspaly
  • 96
  • 3
0

Modifying buttons behaviour, expecially in frameworks, can cause some unexpected issues. You could add a flag to the row and use it to check if the button should be clicked. But you have to know how many click are automatically generated and should be omitted.

var handleClick = function(e) {
  var $button = $(this).find('button');  
  console.log('triggerring click on...', $button);
  if (this.clicked !== true) {
    console.log('and clicked!')
    this.clicked = true;
    $button.trigger('click');
  } else
    this.clicked = false;
};

Here's the code: http://codepen.io/anon/pen/dJroL

Nebril
  • 884
  • 8
  • 17