Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is listening to clicks is not executing in the right order?

I have a top bar icon system like Facebook (friends, msgs, notifications), I want to check if the user clicked on an icon then show the box related to that icon, and if clicked somewhere else on the page then hide the box. To do that I have to always listen to all clicks in the document and check if the click was outside the box or the icon then hide the box. And I don't like to "always listen to all clicks in the document". So to cut in performance I only start to listen for clicks in the document after the user clicks on the icon, and I stop listening for the document after the user clicked somewhere else outside the icon or the box.

The problem now is that I expect this code below to detect the click on the icon and then start listening for all clicks in the document and if the user clicked on another icon then stop listening for all clicks in the document then start the process again.

//this function just checks if the click was outside an element
//http://stackoverflow.com/questions/1403615/use-jquery-to-hide-a-div-when-the-user-clicks-outside-of-it
function clicked_outside(element, e){
        return !element.is(e.target) && element.has(e.target).length === 0;
}
$('.icon').on('click', function(e){
        var object = $(this);
        var box = object.find('.box');
        box.show();
        console.log('start listening for all html clicks outside the element (the icon and the box)');
        $('html').on('click', function(e){
                if (clicked_outside(object, e)){
                        box.hide();
                        console.log('stop listening for all html clicks');
                        $('html').off('click');
                }
        });
});

What happens is the code detect the click on the icon and then start listening for all clicks in the document and if the user clicked on another icon then it starts to listen for all clicks in the document again then stops listening for all clicks in the document

Why is the listening to clicks is not executing in the right order?

Sorry if my explanation was confusing and long, I swear I did my best, here is a jsfiddle to help out.

like image 770
Said Esbaiy Avatar asked Nov 20 '25 19:11

Said Esbaiy


1 Answers

The reason why you have the issue is due to how events work. They start at the element that you click and they work their way up the dom until they hit have a parent anymore or some javascript stops the propagation. So in your code, you would always start the next box click before you could ever stop the previous box click.

Try this to fix that. Also don't use words like "object" as a variable name. It can have very weird results.

function clicked_outside(element, e){
        return !element.is(e.target) && element.has(e.target).length === 0;
}
var obj = null;
$('.icon').on('click', function(e){
        if(obj){
            obj.find('.box').hide();
            $('html').off('click');
        }
        obj = $(this);
        var box = obj.find('.box');
        box.show();
        console.log('start listening for all html clicks outside the element (the icon and the box)');
        $('html').on('click', function(e){
                if (clicked_outside(obj, e)){
                        box.hide();
                        console.log('stop listening for all html clicks');
                        $('html').off('click');
                }
        });
});

Here is another way that doesn't start/stop the listening.

function clicked_outside(element, e){
        return !element.is(e.target) && element.has(e.target).length === 0;
}
var obj = null;
$('.icon').on('click', function(e){
        if(obj){
            obj.find('.box').hide();
        }
        obj = $(this);
        obj.find('.box').show();            
});

$('html').on('click', function(e){
    if (obj && clicked_outside(obj, e)){
            obj.find('.box').hide();
            obj = null;
    }
});
like image 54
Bryan Euton Avatar answered Nov 22 '25 08:11

Bryan Euton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!