3

I'm asked that a click anywhere in a div does a specific action (say collapse it) unless the click was on a link, a button, etc...

Basically, I'd like the reverse of event.preventDefault().

Is there a good and easy way to do this?

I'm looking for a generic solution here; I would like to not assume much about the content of the div.

Might look like:

<div id="click_me>
<p>Clicking here should do stuff
   <a href="http://stackoverflow.com">but not here, nor on the following image</a>
   <a href="/xyz"><img url="/icon.png"/></a>
   imagine buttons... input areas, ...
</p>
</div>

With the following JavaScript:

$("#click_me").click(function(){
  if(black_magic) {
    $("#click_me").toggleClass("collapsed");
  }
});
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166

4 Answers4

4

You just have to make sure the event target is not a link nor a button.

$('#click_me').click(function(e) {
  interactive = 'a, button, input, textarea, video, map, object';
  if($(event.target).closest(interactive).length == 0) ) {
    $("#click_me").toggleClass("collapsed");
  }
});
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
remi
  • 1,293
  • 8
  • 21
  • Doesn't work, for example if the click is on an image inside an `a` – Marc-André Lafortune Jun 30 '10 at 18:27
  • 1
    Getting closer! I edited your answer to make it more complete. Still, I still wish there was an easier way, and one that didn't force me to stop bubbling if I want to attach event handlers to some nested divs. Maybe someone else can come up with a better answer. – Marc-André Lafortune Jun 30 '10 at 19:00
  • instead of interactive="a,button,input" etc, why not just use .closest('.keepDefault') and add that class to every element that needs to do the default behavior? – resopollution Jun 30 '10 at 19:16
  • @resopollution: I feel it's not the responsability of the content that the container behaves in a certain way. The container can be very generic, like a piece of GUI that can be used in many places on the site. – Marc-André Lafortune Jun 30 '10 at 19:27
2

Just add this handler to your link:

$("#click_me a,button,input,textarea,video,map,object").click(function(e){
   e.stopPropagation();
});

To prevent the event to get to the div (bubble up). It will stop so the link will behave correctly.

See it in action. (click preview)

Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
gblazex
  • 49,155
  • 12
  • 98
  • 91
1

Event bubbling is the keyword here. Bind an event handler to the div and check the event target to specify what to do.

$('div.mydivclass').bind('click', function(event){
    switch(event.target.id){
        case 'id_of_an_anchor':{
              alert('anchor was clicked');
              break;
        }
        case 'id_of_a_span':{
              alert('span was clicked');
              break;
        }
        default: {
              alert('something else was clicked within me');
        }
    }
});

Of course you can even check for the targets tagName or nodeType.

jAndy
  • 231,737
  • 57
  • 305
  • 359
0
function onClick(e){
    var gates = "A,INPUT,TEXTAREA,SELECT";
    var bound = this;
    var isCollapse = function ( node ){ 
    if( node == bound ){ return true; }
        var re = new RegExp( "\\b" +node.nodeName+ "\\b", "g" );
        return re.test( gates ) ? false : isCollapse( node.parentNode );
    };

    if( isCollapse( event.srcElement || e.target ) ){
        alert( "collapse" )
        // collapse()
    }
}
document.getElementById("click_me").onclick = onClick;

*fixed * for cases like: <a href="_"><span><strike> a link </strike></span></a>

yulerz
  • 66
  • 3