4

I am not sure this is really bubbling, I will explain.

I have this:

<div>
  <div>
    text here
  </div>
</div>

How to bind an on click event so that it will affect only the enclosed div? If I set it like this:

jQuery('div').bind('click', function() {
  jQuery(this).css('background','blue');
});

it makes blue all the divs. If I add false as the third argument(prevent bubbling) to the bind function it does nothing.

How can I solved this?

Andrew
  • 6,254
  • 16
  • 59
  • 93
  • Have you tried [`stopPropagation()`](https://developer.mozilla.org/en/DOM/event.stopPropagation) in your handler? If there are no ambient capturing handlers, that should be fine, as it prevent the event from reaching any ambient bubbling handlers. – Kerrek SB Aug 26 '11 at 17:22

6 Answers6

7

http://api.jquery.com/event.stopPropagation/

Add event.stopPropagation(); inside the hander.

(It might be better, though, to assign an ID or class to the nested DIV so you can be sure it's the only one affected.)

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
4

You should really use identifiers like IDs or classes, but for your example, you could do this:

jQuery('div > div').bind('click', function() {
  jQuery(this).css('background','blue');
});

...which will bind the handler to any div that is a direct descendant of another div.

So either make your initial selection specific to the element(s) you want to affect, or use event delegation, placing a handler on an ancestor, and testing for the element you want.

Delegation example: http://jsbin.com/ehemac/edit#javascript,live

<div id="container">
    <div class="outer">
      <div>
        text here
      </div>
    </div>
    <div class="outer">
      <div>
        text here
      </div>
    </div>
</div>
jQuery('#container').delegate( '.outer > div', 'click', function() {
    jQuery(this).css('background','blue');
});

This uses the delegate()[docs] method that places a handler on the ancestor with the ID #container.

The first argument to .delegate() is a selector. Any elements that are clicked inside #container will have that selector compared against the element clicked. If the selector matches, the handler will be invoked.

user113716
  • 318,772
  • 63
  • 451
  • 440
  • 1
    Again this doesn't work if your div is nested more than element down (eg `
    here
    `), which would set the background always on the second element (http://jsbin.com/ehemac/2/edit).
    – vol7ron Aug 26 '11 at 18:44
  • From my answer: *"You should really use identifiers like IDs or classes...but for your example, you could do..."*. I didn't say the first code example would work in other situations. My main answer is to properly identify elements on the page. – user113716 Aug 26 '11 at 21:08
  • And it's funny, normally I'm answering what the person is asking, not what they're wanting. Here, the roles are reversed. Though, I still do firmly believe there should either be an element id, or classname to work on. – vol7ron Aug 26 '11 at 22:02
  • Yeah, it's always a judgement call when we see a question that says *"I have this:"* `
    text here
    `. In the back of my mind I'm thinking... really? That's your markup? ;)
    – user113716 Aug 26 '11 at 22:06
  • Hahaha... I would buy you a drink for making me laugh – vol7ron Aug 26 '11 at 22:09
2

http://jsfiddle.net/vol7ron/WzSkj/

Targeting the last descendant


Credit to Patrick DW:

jQuery('div:not(:has(div))').bind('click', function() {
   jQuery(this).css('background','blue');
});

This should be all you need as it will look at all div and find those that don't have child divs (thus, they will be the last descendant of that element type. You could further filter this to make sure they have a parent that is a div, if you wanted to exclude those divs that are standalone.



Older Answer:

This is not by any means meant to be a complete/robust plugin. It serves as only an example of how to target the last element in a chain. See the revision history for a way to do it w/o the plugin. This should be modified if you wish to use it for production.

Plugin:

(function($){
   $.fn.lastDescendant = function(el){
      var found = jQuery(el + ':first').siblings(el).andSelf();
      var prev, curr;
      var stack = this;
      for (var i=0,n=found.length; i<n; i++){
         curr = found.eq(i).find(el);
         while (curr.length){
            prev = curr;
            curr = curr.find(el);
         }         
         stack = stack.add(prev);
      }
      return stack;
   };
})( jQuery );

Example Call:

jQuery.fn.lastDescendant('div')
      .click(function(){
         jQuery(this).css("background","#09c");
      });

Note:

  • this will not select the first (ancestor) element. If you want to select that as well, you could wrap the whole thing in a new div, and then do the above.
  • if I were to make this a production plugin, I would include checking the parameter, and allow you to be able to pass in an object and a starting point (so that siblings are not selected)
Community
  • 1
  • 1
vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • 1
    +1 for the plugin, although we can get identical behavior (except for your *"this should't work"* div) by doing `$('div:not(:has(div))')`, or more generically `$('*:not(:has(*))')` to target any element that doesn't have a nested element. – user113716 Aug 26 '11 at 21:19
  • Nice patrick, that would work, and may be a much better option. I'm trying to update it for passing in strings, objects, and jQuery objects. – vol7ron Aug 26 '11 at 21:52
0

To fix this just use a more specific selector

jQuery('div > div').bind('click', function() {
  jQuery(this).css('background','blue');
})
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
0

The best way to solve it would be to give your inner div an identifiable feature such as a class, e.g., <div class="inner"></div>.

Alternatively, change your selector:

$('div > div').click(function() {
    $(this).css('background', 'blue');
}
Finbarr
  • 31,350
  • 13
  • 63
  • 94
0

try giving the inner div an id tag and refer to it...

<div><div id=foo>text goes here</div></div>


...

$('#foo').bind('click', function() {
  $(this).css('background','blue');
});

HTH -- Joe

Mindfulgeek
  • 141
  • 4