jQuery Context Menu Unbind Click Fix

Updated on May 28, 2009, due to partial fix. The fix should now be a complete fix.

Apologies for the somewhat confusing title.
I’ve been doing a lot of jQuery work, replacing all the AJAX.NET crap in my project at work to speed the interface up. I’ve started using the awesome jQuery Context Menu plugin. However, I found it was also messing around with jsTree which I am using on the same page.

The problem is that the jQuery Context menu overzealously unbinds all click events from the document. This means that it’s going to break all your other Javascript that relies on clicking. Checking the documentation for jQuery’s unbind function, you can see that it accepts a function as a second parameter. This is the function that will be unbound if you pass that in as a parameter.
So, I fixed the jQuery Context Menu by changing the following:

  1. In the main contextMenu function, near the end, just above the return statement, I added the following:
    // External click event for document
    function onDocumentClick(e) {
          var menu = $('#' + o.menu);
          $(document).unbind('click', onDocumentClick).unbind('keypress');
          $(menu).fadeOut(o.outSpeed);
          return false;
    }
    
  2. Next, I change the function that assigns the click listener to the document to assign the defined function, instead of an anonymous function. So, change:
    // Hide bindings
    setTimeout( function() { // Delay for Mozilla
          $(document).click( function() {
                $(document).unbind('click').unbind('keypress');
                $(menu).fadeOut(o.outSpeed);
                return false;
          });
    }, 0);
    

    to

    // Hide bindings
    setTimeout(function() { // Delay for Mozilla
          $(document).click(onDocumentClick);
    }, 0);
    
  3. Lastly, I remove all instances of:
    $(document).unbind('click');
    

That’s it. That fixed the problem for me. You’ll notice I don’t bother with the keypress bindings. That’s because I’m not using them, so I’m not bothered. I’m assuming the fix for that will be a similar strategy, for those who are bothered.

I’ve uploaded my version for those who can’t get it working using the tips in this post, but remember the copyright remains with Cory S.N. LaViska over at A Beautiful Site.
jquery.contextMenu.js

Tags: , ,

  • Rob B
    Thanks so much! This sorted everything out perfectly! Awesome!
  • Kevin
    I have a strange issue and this seems to be the only place on google I could track down that has done extra work with this. Basically, I am trying to dynamically have multiple menus for the same div, and the menu that comes up will be based on the item you are currently hovering over.

    It seems as though what is happening is that as soon as the menu is loaded for a div, it stays there. Do you know a way to possibly destroy the current menu and reload a new menu on every mouse click on a div?
  • Richard
    Thank you so much for this article, this bug haunted me for like forever.
  • Thanks a lot for your fix!
    I think I had the same problem as Thomas. When I clicked once outside the context menu, it disapeared as expected, but then it would never show again because as soon as it shows, the onDocumentClick would kick in and hide it again.

    I fixed it by changing this line:
    $(document).unbind("click", this)
    to
    $(document).unbind("click", onDocumentClick)

    The this in the onDocumentClick function is not the function itself.

    Another thing I fixed:
    somehow the unbind of the menu elements was not working for me. When you choose the Edit menu for the first time the Alert shows up once. When you then right-click and choose edit again, the alert shows 2 times, then 3 times etc.
    I fixed that by unbinding the click event in the click event handler of the menu item:
    $('#' + o.menu).find('li:not(.disabled) a').click(function() {
    $(this).unbind('click');
    ...

    hope it helps someone. took me some time to figure out
  • Tim
    Hey Peter, thanks for that. I'll look at the full copy of the source I keep and see if I can roll those into it.
  • Thomas
    Hi,

    I am using your modifications because of the unbinding of the click events was breaking links on my pages. I am now seeing that if the user clicked to make the menu appear and then clicked off the menu with out making a selection (like they changed their mind about the context menu) then all of the links (a href) on the page are dead. I looked at the js file provided and you created the function

    // External click event for document
    function onDocumentClick(e) {
    var menu = $('#' + o.menu);
    $(document).unbind('click', this).unbind('keypress');
    $(menu).fadeOut(o.outSpeed);
    return false;
    }

    that accepts an argument 'e'. The argument isn't used in the function and the places in the code where you call this function you don't pass a value so I'm wondering if it is a typo??

    Thanks for modifying the script - the unbinding of the click events was really screwing up what I was trying to do. Otherwise it was just fine...
  • Tim
    Hi Thomas,

    The e argument is an argument passed into all event handlers from jQuery, and you're right that I don't use it. It's just a habit of mine that I include all arguments passed into functions in their definitions, probably because static languages like C# will complain and not compile if you haven't declared them.

    If you'd prefer to remove it, it shouldn't impact the code at all.
  • Ral
    Is there a way to make this context menu work with "live" event binding way instead simply bind / unbind?
    I want to add to a grid new rows and they should also have a context menu.
    Thanks!
  • Tim
    I use the context menu in the same way, and as I create new DOM elements I just call contextMenu on them and supply the menu ID and your item functions:

    $(".context-item").contextMenu({ menu: 'context-menu' },
    function(action, el, pos) {
    //Actions
    }
    );
blog comments powered by Disqus