Selecting all elements except for div not working with jQuery

167 Views Asked by At

I'm trying to select all elements in the document except for the #private_chat_menu element and attach a mouseup trigger function to them. However, it runs the function regardless of whether I click a select box inside the #private_chat_menu element or not. Here is the code:

<script>
$("*:not(#private_chat_menu > *)", "body").mouseup(function(e)
{
    var chat_user_container = $('#private_chat_menu');
    var chat_container = $('#chat-wrapper');

    if (chat_container.css("visibility") == 'visible' && chat_user_container.is(':visible'))
    {
        chat_user_container.hide();
    }
});
</script>

<div id="chat-wrapper">
   <div id="private_chat_menu">
      <select id="chat_user_select" name="chat_user_select">
         <option value="">Select Assigned User</option>
         <option value="1">...</option>
         <option value="2">...</option>
      </select>
   </div>
</div>

JSFiddle: http://jsfiddle.net/q0ky2f56/

2

There are 2 best solutions below

3
On BEST ANSWER

Given your requirement it would perform better (and have simpler logic) if you attached a single event handler to the document and interrogate the element which raised the event. If it was the #private_chat_menu, or a child of it, do no work. Something like this:

var $chat_user_container = $('#private_chat_menu');
var $chat_container = $('#chat-wrapper');

$(document).on('mouseup', function(e) {
  var $target = $(e.target);
  if ($target.is($chat_user_container) || $target.closest($chat_user_container).length)
    return;

  if ($chat_container.is(':visible') && $chat_user_container.is(':visible')) {
    $chat_user_container.hide();
  }
});
1
On

Firstly, use event delegation via .on(). Far cleaner and easier to maintain than binding events to multiple elements. With delegation, we bind the event once (to a top-level element e.g. body) and then, when it runs, ascertain whether we want it to proceed for the target element that triggered the event.

We can do this by passing a selector as the second param to on(), but in your case, since the logic as to whether the event should run is non-trivial, it might be easier to test for this in the callback.

The key is to except both #private_chat_menu AND its childen/descendents.

$('body').on('mouseup', '*', function(e) {
    if ($(this).closest('#private_chat_menu').length) return;
    //safe to continue...
});

closest() says: "does the current or any parent/ancestor elements match the passed selector?" If yes, we know we shouldn't allow the event to run.