最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Hiding Bootstrap Popover on Click Outside Popover - Stack Overflow

programmeradmin0浏览0评论

I'm trying to hide the Bootstrap Popover when the user clicks anywhere outside the popover. (I'm really not sure why the creators of Bootstrap decided not to provide this functionality.)

I found the following code on the web but I really don't understand it.

// Hide popover on click anywhere on the document except itself
$(document).click(function(e) {
    // Check for click on the popup itself
    $('.popover').click(function() {
        return false; // Do nothing
    });  
    // Clicking on document other than popup then hide the popup
    $('.pop').popover('hide');  
});

The main thing I find confusing is the line $('.popover').click(function() { return false; });. Doesn't this line add an event handler for the click event? How does that prevent the call to popover('hide') that follows from hiding the popover?

And has anyone seen a better technique?

Note: I know variations of this question has been asked here before, but the answers to those questions involve code more complex than the code above. So my question is really about the code above

I'm trying to hide the Bootstrap Popover when the user clicks anywhere outside the popover. (I'm really not sure why the creators of Bootstrap decided not to provide this functionality.)

I found the following code on the web but I really don't understand it.

// Hide popover on click anywhere on the document except itself
$(document).click(function(e) {
    // Check for click on the popup itself
    $('.popover').click(function() {
        return false; // Do nothing
    });  
    // Clicking on document other than popup then hide the popup
    $('.pop').popover('hide');  
});

The main thing I find confusing is the line $('.popover').click(function() { return false; });. Doesn't this line add an event handler for the click event? How does that prevent the call to popover('hide') that follows from hiding the popover?

And has anyone seen a better technique?

Note: I know variations of this question has been asked here before, but the answers to those questions involve code more complex than the code above. So my question is really about the code above

Share Improve this question asked Jul 24, 2013 at 18:34 Jonathan WoodJonathan Wood 67.2k82 gold badges300 silver badges526 bronze badges 9
  • Read this: stackoverflow.com/questions/1357118/… – Icarus Commented Jul 24, 2013 at 18:44
  • @Icarus: Thanks but that doesn't really answer my question. I know that returning false stops further processing, but how does adding a click handler alter the behavior of the line that follows? And wouldn't this stop the click from working after the popover has been closed? – Jonathan Wood Commented Jul 24, 2013 at 18:49
  • That code does exactly what you described. Everytime someone clicks anywhere on the document (including .popover) it will add an event listener that does absolutely nothing. it's just a waste of memory, since there can be many event listeners on the same element, for the same event and they are just gonna end up stacking on each other – Dogoku Commented Jul 24, 2013 at 18:55
  • @Dogoku: Thanks, but why would the click handler even come into play when calling popover('hide')? Also, does the new handler get removed when the method returns? – Jonathan Wood Commented Jul 24, 2013 at 18:58
  • 1 It should answer your question, at least this line should: "return false from within a jQuery event handler is effectively the same as calling both e.preventDefault and e.stopPropagation". In your code example, the return false inside the popover click handler will stop the propagation to the click event handler for the document, hence, not hiding it. – Icarus Commented Jul 24, 2013 at 19:14
 |  Show 4 more comments

5 Answers 5

Reset to default 8

I made http://jsfiddle.net/BcczZ/2/, which hopefully answers your question

Example HTML

<div class="well>
    <a class="btn" data-toggle="popover" data-content="content.">Popover</a>
    <a class="btn btn-danger bad">Bad button</a>
</div>

JS

var $popover = $('[data-toggle=popover]').popover();

//first event handler for bad button
$('.bad').click(function () {
    alert("clicked");
});


$(document).on("click", function (e) {
    var $target = $(e.target),
    var isPopover = $target.is('[data-toggle=popover]'),
        inPopover = $target.closest('.popover').length > 0

    //Does nothing, only prints on console and wastes memory. BAD CODE, REMOVE IT
    $('.bad').click(function () { 
        console.log('clicked');
        return false;
    });

    //hide only if clicked on button or inside popover
    if (!isPopover && !inPopover) $popover.popover('hide');
});

As I mentioned in my comment, event handlers don't get overwritten, they just stack. Since there is already an event handler on the .bad button, it will be fired, along with any other event handler

Open your console in the jsfiddle, press 5 times somewhere on the page (not the popover button) and then click bad button you should see clicked printed the same amount of times you pressed

Hope it helps


P.S: If you think about it, you already saw this happening, especially in jQuery. Think of all the $(document).ready(...) that exist in a page using multiple jquery plugins. That line just registers an event handler on the document's ready event

I just did a more event based solution.

var $toggle = $('.your-popover-button');
$toggle.popover();

var hidePopover = function() {
    $toggle.popover('hide');
};

$toggle.on('shown', function () {
    var $popover = $toggle.next();
    $popover.on('mousedown', function(e) {
        e.stopPropagation();
    });
    $toggle.on('mousedown', function(e) {
        e.stopPropagation();
    });
    $(document).on('mousedown',hidePopover);
});

$toggle.on('hidden', function () {
    $(document).off('mousedown', hidePopover);
});

short answer insert this to bootstrap min.js

when popout onblur will hide popover
when popout more than one, older popover will be hide

$count=0;$(document).click(function(evt){if($count==0){$count++;}else{$('[data-toggle="popover"]').popover('hide');$count=0;}});$('[data-toggle="popover"]').popover();$('[data-toggle="popover"]').on('click', function(e){$('[data-toggle="popover"]').not(this).popover('hide');$count=0;});

None of the above solutions worked 100% for me because I had to click twice on another, or the same, popover to open it again. I have written the solution from scratch to be simple and effective.

   $('[data-toggle="popover"]').popover({
        html:true,
        trigger: "manual",
        animation: false
    });

    $(document).on('click','body',function(e){
        $('[data-toggle="popover"]').each(function () {
            $(this).popover('hide');
        });

        if (e.target.hasAttribute('data-toggle') && e.target.getAttribute('data-toggle') === 'popover') {
            e.preventDefault();
            $(e.target).popover('show');
        }
        else if (e.target.parentElement.hasAttribute('data-toggle') && e.target.parentElement.getAttribute('data-toggle') === 'popover') {
            e.preventDefault();
            $(e.target.parentElement).popover('show');
        }
    });

My solution, works 100%, for Bootstrap v3

$('html').on('click', function(e) {
    if(typeof $(e.target).data('original-title') !== 'undefined'){
         $('[data-original-title]').not(e.target).popover('hide');
    }

    if($(e.target).parents().is('[data-original-title]')){
         $('[data-original-title]').not($(e.target).closest('[data-original-title]')).popover('hide');
    }

    if (typeof $(e.target).data('original-title') == 'undefined' &&
!$(e.target).parents().is('.popover.in') && !$(e.target).parents().is('[data-original-title]')) {
        $('[data-original-title]').popover('hide');
    }
});
发布评论

评论列表(0)

  1. 暂无评论