javascriptbackgrounddom-eventstablerow

How to get Javascript event to fire only when the background is clicked (and not other elements)?


I'm trying to write a web app which replaces the context menu (right-click menu) with my own customized ones. I want it so that when the user clicks on a table row, they get one certain context menu and when they click on the background of the page, they get a different one.

I have already written the menus and gotten them working. The problem comes in when trying to figure out how to get the background's menu to show ONLY when clicking on the background and how to get the table row's menu to show when that is clicked.

I tried using document.body.oncontextmenu for the body and and setting the oncontextmenu function for each table row, but the body's oncontextmenu function overrides the row's so I get the wrong menu. The menu for the table rows DOES work if I stop using the body's menu, so that's not the issue.

I could be using the wrong events, so is there a different event for just the background (and not the elements on top of the background)? Or a way to "prioritize" the events so the table row's function takes precedence?

This is how the code looks:

var tableMenu;
var bodyMenu;

window.onload = function()
{
    bodyMenu = new rightClickMenu("bodyMenu");
    document.body.oncontextmenu = function() { bodyMenu.show(); tableMenu.hide(); }
    bodyMenu.add("Add Entry", function()
    {
        alert("ADD");
    });
    
    tableMenu = new rightClickMenu("tableMenu", "tblSims");

    simRows = getElementsByClassName("trSimRow");
    for (var i in simRows)
        simRows[i].oncontextmenu = function() { tableMenu.show(this.id.substring(2)); bodyMenu.hide(); }

    tableMenu.add("Delete Entry", function(mac)
    {
        alert("DELETE");
    });
    
    document.body.onclick = function()
    {
        bodyMenu.hide();
        tableMenu.hide();
    };
}

Solution

  • You have to work with the Javascript Event Propagation model. What happens is that your click event is automatically passed down the layers of objects on a page that have been registered as event listeners, unless you explicitly tell it to stop, try something like this:

    function setupClickHandlers()
    {
        document.getElementsByTagName('body')[0].onclick = doBodyMenu;
        document.getElementById('tableID').onclick = doTableMenu;
    }
    
    function doBodyMenu()
    {
        //do whatever it does
    }
    
    function doTableMenu(e)
    {
        //do whatever it does
    
        //stop the event propagating to the body element
        var evt = e ? e : window.event;
    
        if (evt.stopPropagation) {evt.stopPropagation();}
        else {evt.cancelBubble=true;}
        return false;
    }
    

    This should deal with the way each browser handles events.