29

I have the following HTML:

<div class="server" id="32">
  <a>Server Name</a>
  <div class="delete-server">X</div>
</div>

I am trying to make it so when users click the server div it brings up an edit dialog. The problem is simply doing:

 $(".server").click(function () {
     //Show edit dialog
 });

Does not work, because if they click the X which is delete, it brings up the edit dialog. How can make the entire div server have the click event except the delete-server div.

gdoron
  • 147,333
  • 58
  • 291
  • 367
Justin
  • 42,716
  • 77
  • 201
  • 296
  • You should be aware of that your accepted answer uses delegate event for no good reason. you can read the `on` [docs](http://api.jquery.com/on/) to learn what it does. – gdoron Apr 15 '12 at 08:45
  • @gdoron - Can you please provide a source for your claim that event delegation is slower? AFAIK, event delegation does the same thing you did, but behind the scenes; it checks if the target element matches the given selector. I might be wrong though, and would love to be enlightened. – Joseph Silber Nov 20 '12 at 17:23
  • related http://stackoverflow.com/questions/12690313/jquery-on-click-on-everything-but-a-div-and-its-children/12690357 – Adriano Jun 05 '14 at 15:36

4 Answers4

37
$(".server").on('click', ':not(.delete-server)', function (e) {
     e.stopPropagation()
     // Show edit dialog
});

Here's the fiddle: http://jsfiddle.net/9bzmz/3/

Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
26

Just check what is the element who triggered the event:

$(".server").click(function(e) {
    if (!$(e.target).hasClass('delete-server')) {
        alert('Show dialog!');
    }
});​

LIVE DEMO

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • Still seeing edit dialog coming up when clicking X, I think this is because the click event is firing on `.server` so it doesn't know about the child div `.delete-server`. – Justin Apr 15 '12 at 07:19
  • @Justin. Check out the updated answer. You should be aware of that your accepted answer make a `delegate event` instead of `direct event`, which is slower, and has no reason to do it. delegate event should be used of dynamically change DOM structure. – gdoron Apr 15 '12 at 08:40
  • Can you please provide a source for your claim that event delegation is slower? AFAIK, event delegation does the same thing you did, but behind the scenes; it checks if the target element matches the given selector. I might be wrong though, and would love to be enlightened. – Joseph Silber Apr 15 '12 at 14:40
11

There is an alternative way to solve this:

$(".server").click(function () {
    // show edit dialog
});
$(".delete-server").click(function (event) {
    // show delete dialog for $(this).closest(".server")
    event.stopPropagation();
});

Just make sure a click event issued on .delete-server does not bubble up to the parent element.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • +1 Nice way, though it uses two handlers while it can be done with checking the `target` element. [check this](http://stackoverflow.com/a/10160231/601179) – gdoron Apr 15 '12 at 08:43
  • @gdoron Yes, but where would be the elegance in this? That would lead to a single event handler with an `if`/`switch` check inside it to determine what the event is *actually* supposed to do. I'd consider this rather smelly. – Tomalak Apr 15 '12 at 08:46
  • Well.. there is no wrong way, I like mine better. Each way is better then the accepted answer which uses delegate event for no good reason... :) – gdoron Apr 15 '12 at 08:47
  • @gdoron From a pragmatic point of view, *everything* that works is fine. Based on that the accepted answer is no worse than yours or mine. Architecturally, it is better to handle separate concerns separately. Your approach taken to the extreme would be one big `$("body").click()` event handler with an enormous `switch` statement inside. I think we can agree that this would be ugly. Doing the same on a smaller scale still is ugly. :) – Tomalak Apr 15 '12 at 08:54
  • 2
    The accepted answer solves the problem posed but this solution has the benefit of preventing would-be child elements in the `
    ` element from bubbling as well
    – Ian Lunn Dec 01 '15 at 11:02
0

Only this works for me.

js_object is jQuery object for meta parent like a $('body')

jq_object.on('click', '.js-parent :not(.js-child-1, .js-child-2)', function(event) {
    //your code
});

jq_object.on('click', '.js-child-1', function(event) {
    //your code
});

jq_object.on('click', '.js-child-2', function(event) {
    //your code
});

Fore your case:

server — js-parent

delete-server — js-child-1

jq_object.on('click', '.server :not(.delete-server)', function(event) {
    //your code
});

jq_object.on('click', '.delete-server', function(event) {
    //your code
});
German Khokhlov
  • 1,724
  • 16
  • 15