1

I'm writing an application and I need to return a class of an element that I have clicked on.

Problem is that once I click on an element, I also get all of it's parents classes.

Code I use to retrieve class names:

$('div').click(function () {
    console.log($(this).attr("class"));
});

This is a sample of elements:

<div class="parent">
    <div class="child">
        Bla bla bla
    </div>
</div>

Once I click on a .child div, it returns me both .child and .parent class names.

I suppose there should be an easy way to fix this, but after a couple of hours of research I couldn't find anything.

gdoron
  • 147,333
  • 58
  • 291
  • 367
Alvydas
  • 354
  • 1
  • 5
  • 15
  • Just try `return false;` on click function, after `console.log` - it does the event stop on first function call. If you want apply the function only over div.child, just change the first line to `$('div.child')...` – David Rodrigues Jan 31 '12 at 17:41
  • With `JQuery` there is always an easy way to fix things. Thanks `JQuery`! – gdoron Jan 31 '12 at 18:17

7 Answers7

5

You need to prevent the event from bubbling to the parent elements, use return false;

$('div').click(function (e) {
    console.log($(this).attr("class"));
    return false; // or e.stopPropagation();

});    

return false from within a jQuery event handler is effectively the same as calling both e.preventDefault and e.stopPropagation on the passed jQuery.Event object. ........

Read this excellent answer for more info.

With <div> there is now difference between e.stopPropagation() and return false because <div> doesn't have a default click event like <a> or <button> do.

Community
  • 1
  • 1
gdoron
  • 147,333
  • 58
  • 291
  • 367
  • Or you need to stopPropigation – Nick Bork Jan 31 '12 at 17:43
  • @Splash-X in jQuery returning false does that for you. – Alnitak Jan 31 '12 at 17:44
  • @Splash-X. I added that option, though it doesn't matter because `div` hasn't any default event of `click`... – gdoron Jan 31 '12 at 17:48
  • I knew it had to be something easy! Thanks a lot! – Alvydas Jan 31 '12 at 17:49
  • @Alnitak yes, stopPropagation is the same as returning false, but it can be set anywhere in your method (like the top) without the need to "return". – Nick Bork Jan 31 '12 at 21:08
  • @Splash-X. And it's better to set it anywhere because...? it's exactly the same thing mate! – gdoron Jan 31 '12 at 21:11
  • @gdoron _technically_ there's an argument that calling `e.preventDefault()` and `e.stopPropagation()` at the top of your event handler means that any subsequent exception won't change the behaviour, whereas a `return false` might get skipped. It's slightly tenuous IMHO, since in well designed code that exception shouldn't be possible. – Alnitak Jan 31 '12 at 21:26
2

Don't bind to all <div> elements on the page. That's quite inefficient.

Instead...

  • use event delegation using .on(), binding one handler to the body

  • have the delegation selector test for 'div'

  • then get the .className from the this that was clicked


$('body').on('click', 'div', function(e) {
    console.log(this.className);
    e.stopPropagation();
});

So now you have one handler doing the work for all <div> elements.

If you're using an older version of jQuery, use .delegate() instead of .on().

$('body').delegate('div', 'click', function(e) {
    console.log(this.className);
    e.stopPropagation();
});

EDIT: Updated to use this instead of e.target as suggested by @gdoron.

Community
  • 1
  • 1
  • If the selector of the delegate is 'div' won't it just be `this`? Anyway are you sure that attaching a dynamic delegate to 'body' is more efficient than bind an event to all the divs? It's hard to believe. – gdoron Jan 31 '12 at 18:03
  • @gdoron: If there are many divs on the page that should get the same handler, then it will require less memory overhead to bind only one. There is more processing to do per click, but click events don't happen frequently like scroll or mousemove events. But you're right, I could just use `this`. For some reason I was thinking there would be issues with the nested elements, but it seems that there are not. –  Jan 31 '12 at 18:08
  • @gdoron: Philosophical difference. :) –  Jan 31 '12 at 18:17
1

You need to prevent the click from "bubbling" up to its parent.

In native Javascript you would call ev.stopPropagation() but in jQuery handlers you can just return false in the event handler and jQuery then does the rest.

See JSFiddle for demo.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
0

You added click event to all DIV elements but you need only one.

$('div.child').click(function () {
    console.log($(this).attr("class"));
});
Māris Kiseļovs
  • 16,957
  • 5
  • 41
  • 48
  • He wants to add the parent to the list when the parent (and not the child) was clicked as well. – gdoron Jan 31 '12 at 17:52
0

try to use return false

$('div').click(function() {
    console.log($(this).attr("class"));
    return false;
});
Mattia Larentis
  • 192
  • 1
  • 9
0

You can stop propagation using event.stopPropagation();

$('div').click(function (e) {
    console.log($(this).attr("class"));
    e.stopPropagation();
});
Jamie Dixon
  • 53,019
  • 19
  • 125
  • 162
0

It's because you have included elements. And function executes twice. Once in .child and once in .parent Try,

<div class="parent">BLA BLA</div>
<div class="child">bla bla bla</div>

And see the difference.

sly
  • 149
  • 1
  • 6