How to dismiss a Twitter Bootstrap popover by clicking outside? – Dev

The best answers to the question “How to dismiss a Twitter Bootstrap popover by clicking outside?” in the category Dev.

QUESTION:

Can we get popovers to be dismissable in the same way as modals, ie. make them close when user clicks somewhere outside of them?

Unfortunately I can’t just use real modal instead of popover, because modal means position:fixed and that would be no popover anymore. 🙁

ANSWER:

$('html').on('mouseup', function(e) {
    if(!$(e.target).closest('.popover').length) {
        $('.popover').each(function(){
            $(this.previousSibling).popover('hide');
        });
    }
});

This closes all popovers if you click anywhere except on a popover

UPDATE for Bootstrap 4.1

$("html").on("mouseup", function (e) {
    var l = $(e.target);
    if (l[0].className.indexOf("popover") == -1) {
        $(".popover").each(function () {
            $(this).popover("hide");
        });
    }
});

ANSWER:

Update: A slightly more robust solution: http://jsfiddle.net/mattdlockyer/C5GBU/72/

For buttons containing text only:

$('body').on('click', function (e) {
    //did not click a popover toggle or popover
    if ($(e.target).data('toggle') !== 'popover'
        && $(e.target).parents('.popover.in').length === 0) { 
        $('[data-toggle="popover"]').popover('hide');
    }
});

For buttons containing icons use (this code has a bug in Bootstrap 3.3.6, see the fix below in this answer)

$('body').on('click', function (e) {
        //did not click a popover toggle, or icon in popover toggle, or popover
        if ($(e.target).data('toggle') !== 'popover'
            && $(e.target).parents('[data-toggle="popover"]').length === 0
            && $(e.target).parents('.popover.in').length === 0) { 
            $('[data-toggle="popover"]').popover('hide');
        }
    });

For JS Generated Popovers Use '[data-original-title]' in place of '[data-toggle="popover"]'

Caveat: The solution above allows multiple popovers to be open at once.

One popover at a time please:

Update: Bootstrap 3.0.x, see code or fiddle http://jsfiddle.net/mattdlockyer/C5GBU/2/

$('body').on('click', function (e) {
    $('[data-toggle="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

This handles closing of popovers already open and not clicked on or their links have not been clicked.


Update: Bootstrap 3.3.6, see fiddle

Fixes issue where after closing, takes 2 clicks to re-open

$(document).on('click', function (e) {
    $('[data-toggle="popover"],[data-original-title]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {                
            (($(this).popover('hide').data('bs.popover')||{}).inState||{}).click = false  // fix for BS 3.3.6
        }

    });
});

Update: Using the conditional of the previous improvement, this solution was achieved. Fix the problem of double click and ghost popover:

$(document).on("shown.bs.popover",'[data-toggle="popover"]', function(){
    $(this).attr('someattr','1');
});
$(document).on("hidden.bs.popover",'[data-toggle="popover"]', function(){
    $(this).attr('someattr','0');
});
$(document).on('click', function (e) {
    $('[data-toggle="popover"],[data-original-title]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            if($(this).attr('someattr')=="1"){
                $(this).popover("toggle");
            }
        }
    });
});

ANSWER:

With bootstrap 2.3.2 you can set the trigger to ‘focus’ and it just works:

$('#el').popover({trigger:'focus'});

ANSWER:

Most simple, most fail safe version, works with any bootstrap version.

Demo:
http://jsfiddle.net/guya/24mmM/

Demo 2: Not dismissing when clicking inside the popover content
http://jsfiddle.net/guya/fjZja/

Demo 3: Multiple popovers:
http://jsfiddle.net/guya/6YCjW/


Simply calling this line will dismiss all popovers:

$('[data-original-title]').popover('hide');

Dismiss all popovers when clicking outside with this code:

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

The snippet above attach a click event on the body.
When the user click on a popover, it’ll behave as normal.
When the user click on something that is not a popover it’ll close all popovers.

It’ll also work with popovers that are initiated with Javascript, as opposed to some other examples that will not work. (see the demo)

If you don’t want to dismiss when clicking inside the popover content, use this code (see link to 2nd demo):

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