156

I'm currently using popovers with Twitter Bootstrap, initiated like this:

$('.popup-marker').popover({
        html: true,
        trigger: 'manual'
    }).click(function(e) {
        $(this).popover('toggle');
        e.preventDefault();
    });

As you can see, they're triggered manually, and clicking on .popup-marker (which is a div with a background image) toggles a popover. This works great, but I'd like to also be able to close the popover with a click anywhere else on the page (but not on the popover itself!).

I've tried a few different things, including the following, but with no results to show for it:

$('body').click(function(e) {
    $('.popup-marker').popover('hide');
});

How can I close the popover with a click anywhere else on the page, but not with a click onthe popover itself?

Travis Northcutt
  • 24,666
  • 9
  • 42
  • 51

31 Answers31

106

Presuming that only one popover can be visible at any time, you can use a set of flags to mark when there's a popover visible, and only then hide them.

If you set the event listener on the document body, it will trigger when you click the element marked with 'popup-marker'. So you'll have to call stopPropagation() on the event object. And apply the same trick when clicking on the popover itself.

Below is a working JavaScript code that does this. It uses jQuery >= 1.7

jQuery(function() {
    var isVisible = false;

    var hideAllPopovers = function() {
       $('.popup-marker').each(function() {
            $(this).popover('hide');
        });  
    };

    $('.popup-marker').popover({
        html: true,
        trigger: 'manual'
    }).on('click', function(e) {
        // if any other popovers are visible, hide them
        if(isVisible) {
            hideAllPopovers();
        }

        $(this).popover('show');

        // handle clicking on the popover itself
        $('.popover').off('click').on('click', function(e) {
            e.stopPropagation(); // prevent event for bubbling up => will not get caught with document.onclick
        });

        isVisible = true;
        e.stopPropagation();
    });


    $(document).on('click', function(e) {
        hideAllPopovers();
        isVisible = false;
    });
});

http://jsfiddle.net/AFffL/539/

The only caveat is that you won't be able to open 2 popovers at the same time. But I think that would be confusing for the user, anyway :-)

Radu Cugut
  • 1,663
  • 1
  • 16
  • 18
  • Unfortunately that doesn't do the trick... the popovers open on click, but don't close (regardless of where I click). – Travis Northcutt Jan 24 '12 at 16:44
  • Ahh, looks like it works when there is only one .popup-marker element, but when you add more, it fails: http://jsfiddle.net/AFffL/2/ – Travis Northcutt Jan 24 '12 at 19:28
  • That did it. For future reference, I used multiple selectors to also target elements that are currently hidden, but later become visible (they're on a hidden tab): `$('.popup-marker, .popup-marker:hidden')` – Travis Northcutt Jan 25 '12 at 22:14
  • The popover plugin passes a reference to the popover itself if you use the "placement" parameter as a function (it's the first parameter it passes into the function). Only problem is, there doesn't seem to be a way to bind any event listeners to it. It seems extremely arbitrary that this would be the case, but it might be specifically deafening itself. However, if you could figure out a way to set listeners on the popovers themselves, it would be magnificently easy to simply treat the popovers as entities hooked to their elements. – dclowd9901 Mar 23 '12 at 02:31
  • 1
    Clicking on the popover itself in that jsfiddle causes the popover to hide - not quite what tnorthcutt asked. – Jonathon Hill Apr 06 '12 at 16:03
  • 1
    @RaduCugut thats a great solution. But it has a bug. Click once on zzzzz and the popover shows up. Now click once on the white background. The popup disappears. Now click again on the white background. And now click again on zzzz and it doesn't work. :-| – Houman Sep 08 '12 at 23:28
  • 1
    @Kave you are right, I've modified the fiddle and the answer to correct this. http://jsfiddle.net/AFffL/177/ – Radu Cugut Sep 10 '12 at 14:05
  • when clicking on the popover is close. why? – Chamnap Dec 01 '12 at 04:14
  • 3
    Why not just run $('.popup-marker').popover('hide') (to hide them all) before $(this).popover('show'), which removes the need for any isVisible and clickedAway variables? – Nathan Hangen May 16 '13 at 14:54
  • @NathanHangen `$('.popup-marker').popover('hide')` doesn't actually work to hide all popovers, only the first found. But using `.each()` works. I updated the answer this way. Thanks for the idea. – Radu Cugut May 22 '13 at 17:57
  • 1
    This solution gave me some issues (clicking on the '.popup-marker' element of the opened popover made the popovers not work afterwards). I came up with yet another solution (posted below) that worked for me and seems simpler (I'm using Bootstrap 2.3.1). – RayOnAir Jun 29 '13 at 00:08
  • @RayOnAir, I made an edit about what you mentioned as I experienced a similar problem. Just add an exclude to your hideAll parameter list that allows you to check to see if the current clicked item matches and skip the "hide" action. It has to do with race conditions in JS. – JGood May 05 '15 at 17:47
  • 1
    The elements with popovers are already identified by the `data-toggle="popover"` attribute, so replace the `$('.popup-marker')` selector with `$('[data-toggle="popover"]')` and you don't have to add the popup-marker class to your elements. – Tim Partridge Jul 21 '15 at 19:50
  • 1
    This functionality should be the default – lewis Aug 06 '15 at 18:38
  • .popover is not defined. – chovy Dec 21 '15 at 19:32
  • Hi, in Bootstrap 4 you can use `$('[data-toggle_popover="popover"][aria-describedby]').popover('hide');` inside `show.bs.popover` event – Shimbala Dec 10 '20 at 16:44
77

This is even easier :

$('html').click(function(e) {
    $('.popup-marker').popover('hide');
});

$('.popup-marker').popover({
    html: true,
    trigger: 'manual'
}).click(function(e) {
    $(this).popover('toggle');
    e.stopPropagation();
});
Peter Lang
  • 54,264
  • 27
  • 148
  • 161
prbaron
  • 867
  • 8
  • 19
  • Agreed. And at least for me, that's the right way to do it. The first option seems to be a "quick fix". – Denis Lins Jan 17 '13 at 20:11
  • Too bad I didn't saw your comment before, I had to figure out this way by myself ... – Denis Lins Jan 17 '13 at 20:12
  • 4
    Wished to use this but for some reason didn't work out. The click events never reached `html` because of `e.stopPropagation();` Instead I used something like `$('.popup-marker').on('show', function(event) { $('.popup-marker').filter(function(index, element) { return element != event.target; }).popover('hide'); });` which did the job fine too (don't know if there is a performance difference though) – Cornelis Mar 13 '13 at 18:30
  • 1
    This is the best answer IMO. – Loolooii Mar 22 '13 at 18:17
  • 1
    The compilation of @pbaron 's and @Cornelis answers works best. What I've added is Cornelis code inside second 'click' function (just before `$(this).popover('toggle');` part. Then, if you have multiple 'popup-marker' objects, clicking each one will close the others. – alekwisnia Apr 15 '13 at 11:24
  • 2
    The one problem with this is the popover is still there, just hidden. So for example if you have links in the popover, you can hover your cursor where it used to be and still get the cursor change over those links. – Benjamin Carlsson Oct 01 '13 at 05:53
  • Why does the order of these events seem to matter? The order they are in the example works. If I swap the order they cease to work. – Pseudonymous May 04 '16 at 10:28
  • the only problem with this solutions is that if you click inside the popover, it closes itself anyway, instead it should be closed only when you click outside of the popover – myh34d Mar 29 '17 at 08:57
  • @myh34d to solve that, just include this inside the `click(function(e) {})` function: `$('.popover').off('click').on('click', function(e) { e.stopPropagation(); });`. Also instead of `$('html').click` I use `$(document).click` – cawecoy Nov 10 '18 at 01:17
48

I had a similar need, and found this great little extension of the Twitter Bootstrap Popover by Lee Carmichael, called BootstrapX - clickover. He also has some usage examples here. Basically it will change the popover into an interactive component which will close when you click elsewhere on the page, or on a close button within the popover. This will also allow multiple popovers open at once and a bunch of other nice features.

Plugin can be found here.

Usage example

<button rel="clickover" data-content="Show something here. 
    <button data-dismiss='clickover'
    >Close Clickover</button>"
>Show clickover</button>

javascript:

// load click overs using 'rel' attribute
$('[rel="clickover"]').clickover();
Miika L.
  • 3,333
  • 1
  • 24
  • 35
39

The accepted solution gave me some issues (clicking on the '.popup-marker' element of the opened popover made the popovers not work afterwards). I came up with this other solution that works perfectly for me and it's quite simple (I'm using Bootstrap 2.3.1):

$('.popup-marker').popover({
    html: true,
    trigger: 'manual'
}).click(function(e) {
    $('.popup-marker').not(this).popover('hide');
    $(this).popover('toggle');
});
$(document).click(function(e) {
    if (!$(e.target).is('.popup-marker, .popover-title, .popover-content')) {
        $('.popup-marker').popover('hide');
    }
});

UPDATE: This code works with Bootstrap 3 as well!

RayOnAir
  • 2,038
  • 2
  • 22
  • 33
20

read "Dismiss on next click" here http://getbootstrap.com/javascript/#popovers

You can use the focus trigger to dismiss popovers on the next click, but you have to use use the <a> tag, not the <button> tag, and you also must include a tabindex attribute...

Example:

<a href="#" tabindex="0" class="btn btn-lg btn-danger"
  data-toggle="popover" data-trigger="focus" title="Dismissible popover"
  data-content="And here's some amazing content. It's very engaging. Right?">
  Dismissible popover
</a>
Andrej Sramko
  • 833
  • 7
  • 18
  • 2
    The question stated that he did not want it to dismiss if the click was on the popover. This dismiss it on any click anywhere. – Fred Mar 12 '15 at 13:30
  • 1
    Adding data-trigger="focus" stopped my popovers from launching until I read this post and added the tabindex attribute. Now it works! – PixelGraph Jun 05 '15 at 16:39
  • 2
    For information, this also works with `tooltip`, even if it's not clearly mentioned on the actual doc. – AlexB Oct 21 '15 at 12:49
7

All of the existing answers are fairly weak, as they rely on capturing all document events then finding active popovers, or modifying the call to .popover().

A much better approach is to listen for show.bs.popover events on the document's body then react accordingly. Below is code which will close popovers when the document is clicked or esc is pressed, only binding event listeners when popovers are shown:

function closePopoversOnDocumentEvents() {
  var visiblePopovers = [];

  var $body = $("body");

  function hideVisiblePopovers() {
    $.each(visiblePopovers, function() {
      $(this).popover("hide");
    });
  }

  function onBodyClick(event) {
    if (event.isDefaultPrevented())
      return;

    var $target = $(event.target);
    if ($target.data("bs.popover"))
      return;

    if ($target.parents(".popover").length)
      return;

    hideVisiblePopovers();
  }

  function onBodyKeyup(event) {
    if (event.isDefaultPrevented())
      return;

    if (event.keyCode != 27) // esc
      return;

    hideVisiblePopovers();
    event.preventDefault();
  }

  function onPopoverShow(event) {
    if (!visiblePopovers.length) {
      $body.on("click", onBodyClick);
      $body.on("keyup", onBodyKeyup);
    }
    visiblePopovers.push(event.target);
  }

  function onPopoverHide(event) {
    var target = event.target;
    var index = visiblePopovers.indexOf(target);
    if (index > -1) {
      visiblePopovers.splice(index, 1);
    }
    if (visiblePopovers.length == 0) {
      $body.off("click", onBodyClick);
      $body.off("keyup", onBodyKeyup);
    }
  }

  $body.on("show.bs.popover", onPopoverShow);
  $body.on("hide.bs.popover", onPopoverHide);
}
David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • +1 This is the cleanest and most extensible solution. If you're using a framework like backbone as well, just dump this in your initialization code and it will take care of handling the popovers. – JohnP Apr 09 '14 at 16:28
  • This answer also adds performance concerns and it allows handling more complex HTML within the popover. – Ricardo Dec 15 '17 at 01:23
  • Great solution; was able to drop it into a react method quite easily. One suggestions, add `$(event.target).data("bs.popover").inState.click = false;` to the onPopoverHide function so you don't need to click twice to reopen after closing. – sco_tt Jan 03 '18 at 22:53
  • Curious if you could make a fiddle of this with two popups. In my application when I implemented your code, I was able to click popup to popup and multiple appeared, then clicking the 'body' only removed the last one displayed. – Terry May 16 '20 at 14:18
5

https://github.com/lecar-red/bootstrapx-clickover

It's an extension of twitter bootstrap popover and will solve the problem very simply.

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
Ibrahim
  • 69
  • 1
  • 1
2

For some reason none of the other solutions here worked for me. However, after a lot of troubleshooting, I finally arrived at this method which works perfectly (for me at least).

$('html').click(function(e) {
  if( !$(e.target).parents().hasClass('popover') ) {
    $('#popover_parent').popover('destroy');
  }
});

In my case I was adding a popover to a table and absolutely positioning it above/below the td that was clicked. The table selection was handled by jQuery-UI Selectable so I'm not sure if that was interfering. However whenever I clicked inside the popover my click handler which targeted $('.popover') never worked and the event handling was always delegated to the $(html) click handler. I'm fairly new to JS so perhaps I'm just missing something?

Anyways I hope this helps someone!

moollaza
  • 480
  • 7
  • 8
  • BTW I'm not sure if it matters, but I used this method for Bootstrap 2. I assume it will work for Bootstrap 3, but have not confirmed. – moollaza Mar 06 '14 at 18:28
2

I give all my popovers anchors the class activate_popover. I activate them all at once onload

$('body').popover({selector: '.activate-popover', html : true, container: 'body'})

to get the click away functionality working I use (in coffee script):

$(document).on('click', (e) ->
  clickedOnActivate = ($(e.target).parents().hasClass("activate-popover") || $(e.target).hasClass("activate-popover"))
  clickedAway = !($(e.target).parents().hasClass("popover") || $(e.target).hasClass("popover"))
if clickedAway && !clickedOnActivate
  $(".popover.in").prev().popover('hide')
if clickedOnActivate 
  $(".popover.in").prev().each () ->
    if !$(this).is($(e.target).closest('.activate-popover'))
      $(this).popover('hide')
)

Which works perfectly fine with bootstrap 2.3.1

  • This worked for me, except that I had to get rid of `.prev()` in the first `if` clause. I'm using Bootstrap 3.2.0.2, maybe there's a difference? Also, you can just leave out the entire second `if` clause if would you like to be able to have multiple pop-ups open at the same time. Just click anywhere that isn't an popover-activating-element (class 'activate-popover' in this example) to close all the open popovers. Works great! – Andrew Swihart Oct 19 '14 at 14:51
2

Even though there are a lot of solutions here, i'd like to propose mine as well, i don't know if there is some solution up there that solves it all, but i tried 3 of them and they had issues, like clicking on the popover it self makes it hide, others that if i had another popover buttons clicked both/multiple popovers would still appear (like in the selected solution), How ever, This one fixed it all

var curr_popover_btn = null;
// Hide popovers function
function hide_popovers(e)
{
    var container = $(".popover.in");
    if (!container.is(e.target) // if the target of the click isn't the container...
        && container.has(e.target).length === 0) // ... nor a descendant of the container
    {
        if( curr_popover_btn != null )
        {
            $(curr_popover_btn).popover('hide');
            curr_popover_btn = null;
        }
        container.hide();
    }
}
// Hide popovers when out of focus
$('html').click(function(e) {
    hide_popovers(e);
});
$('.popover-marker').popover({
    trigger: 'manual'
}).click(function(e) {
    hide_popovers(e);
    var $popover_btns = $('.popover-marker');
    curr_popover_btn = this;
    var $other_popover_btns = jQuery.grep($($popover_btns), function(popover_btn){
                return ( popover_btn !== curr_popover_btn );
            });
    $($other_popover_btns).popover('hide');
    $(this).popover('toggle');
    e.stopPropagation();
});
Roshdy
  • 1,703
  • 3
  • 25
  • 34
2

I would set the focus to the newly created pop-over and remove it on blur. That way it's not needed to check which element of the DOM has been clicked and the pop-over can be clicked, and selected too: it will not lose its focus and will not disappear.

The code:

    $('.popup-marker').popover({
       html: true,
       trigger: 'manual'
    }).click(function(e) {
       $(this).popover('toggle');
       // set the focus on the popover itself 
       jQuery(".popover").attr("tabindex",-1).focus();
       e.preventDefault();
    });

    // live event, will delete the popover by clicking any part of the page
    $('body').on('blur','.popover',function(){
       $('.popup-marker').popover('hide');
    });
trincot
  • 317,000
  • 35
  • 244
  • 286
Luca Vizzi
  • 31
  • 1
1

Here is the solution which worked very fine for me, if it can help :

/**
* Add the equals method to the jquery objects
*/
$.fn.equals = function(compareTo) {
  if (!compareTo || this.length !== compareTo.length) {
    return false;
  }
  for (var i = 0; i < this.length; ++i) {
    if (this[i] !== compareTo[i]) {
      return false;
    }
  }
  return true;
};

/**
 * Activate popover message for all concerned fields
 */
var popoverOpened = null;
$(function() { 
    $('span.btn').popover();
    $('span.btn').unbind("click");
    $('span.btn').bind("click", function(e) {
        e.stopPropagation();
        if($(this).equals(popoverOpened)) return;
        if(popoverOpened !== null) {
            popoverOpened.popover("hide");            
        }
        $(this).popover('show');
        popoverOpened = $(this);
        e.preventDefault();
    });

    $(document).click(function(e) {
        if(popoverOpened !== null) {
            popoverOpened.popover("hide");   
            popoverOpened = null;
        }        
    });
});
Gilles Hemmerlé
  • 439
  • 3
  • 10
1

Here's my solution, for what it's worth:

// Listen for clicks or touches on the page
$("html").on("click.popover.data-api touchend.popover.data-api", function(e) {

  // Loop through each popover on the page
  $("[data-toggle=popover]").each(function() {

    // Hide this popover if it's visible and if the user clicked outside of it
    if ($(this).next('div.popover:visible').length && $(".popover").has(e.target).length === 0) {
      $(this).popover("hide");
    }

  });
});
nates
  • 8,312
  • 5
  • 32
  • 28
1

I had some problem to get it working on bootstrap 2.3.2. But i sloved it this way:

$(function () {
  $(document).mouseup(function (e) {
        if(($('.popover').length > 0) && !$(e.target).hasClass('popInfo')) {
            $('.popover').each(function(){
                $(this).prev('.popInfo').popover('hide');
            });
        }
    });

    $('.popInfo').popover({
        trigger: 'click',
        html: true
    });
});
oBo
  • 992
  • 2
  • 13
  • 28
1

tweaked @David Wolever solution slightly:

function closePopoversOnDocumentEvents() {
  var visiblePopovers = [];

  var $body = $("body");

  function hideVisiblePopovers() {
    /* this was giving problems and had a bit of overhead
      $.each(visiblePopovers, function() {
        $(this).popover("hide");
      });
    */
    while (visiblePopovers.length !== 0) {
       $(visiblePopovers.pop()).popover("hide");
    }
  }

  function onBodyClick(event) {
    if (event.isDefaultPrevented())
      return;

    var $target = $(event.target);
    if ($target.data("bs.popover"))
      return;

    if ($target.parents(".popover").length)
      return;

    hideVisiblePopovers();
  }

  function onBodyKeyup(event) {
    if (event.isDefaultPrevented())
      return;

    if (event.keyCode != 27) // esc
      return;

    hideVisiblePopovers();
    event.preventDefault();
  }

  function onPopoverShow(event) {
    if (!visiblePopovers.length) {
      $body.on("click", onBodyClick);
      $body.on("keyup", onBodyKeyup);
    }
    visiblePopovers.push(event.target);
  }

  function onPopoverHide(event) {
    var target = event.target;
    var index = visiblePopovers.indexOf(target);
    if (index > -1) {
      visiblePopovers.splice(index, 1);
    }
    if (visiblePopovers.length == 0) {
      $body.off("click", onBodyClick);
      $body.off("keyup", onBodyKeyup);
    }
  }

  $body.on("show.bs.popover", onPopoverShow);
  $body.on("hide.bs.popover", onPopoverHide);
}
Lee Gary
  • 2,357
  • 2
  • 22
  • 38
1

This question was also asked here and my answer provides not only a way to understand jQuery DOM traversal methods but 2 options for handling the closing of popovers by clicking outside.

Open multiple popovers at once or one popover at a time.

Plus these small code snippets can handle the closing of buttons containing icons!

https://stackoverflow.com/a/14857326/1060487

Community
  • 1
  • 1
mattdlockyer
  • 6,984
  • 4
  • 40
  • 44
1

This one works like a charm and I use it.

It will open the popover when you click and if you click again it will close, also if you click outside of the popover the popover will be closed.

This also works with more than 1 popover.

    function hideAllPopovers(){
    $('[data-toggle="popover"]').each(function() {
        if ($(this).data("showing") == "true"){
            $(this).data("showing", "false");
            $(this).popover('hide');                
        }
    });
}
$('[data-toggle="popover"]').each(function() {
        $(this).popover({
            html: true,
            trigger: 'manual'
        }).click(function(e) {
            if ($(this).data("showing") !=  "true"){
                hideAllPopovers();
                $(this).data("showing", "true");
                $(this).popover('show');
            }else{
                hideAllPopovers();
            }
            e.stopPropagation();
        });
});

$(document).click(function(e) {
    hideAllPopovers();
});
Patrick Nogueira
  • 186
  • 2
  • 11
1

Another solution, it covered the problem I had with clicking descendants of the popover:

$(document).mouseup(function (e) {
    // The target is not popover or popover descendants
    if (!$(".popover").is(e.target) && 0 === $(".popover").has(e.target).length) {
        $("[data-toggle=popover]").popover('hide');
    }
});
0

I do it as below

$("a[rel=popover]").click(function(event){
    if(event.which == 1)
    {   
        $thisPopOver = $(this);
        $thisPopOver.popover('toggle');
        $thisPopOver.parent("li").click(function(event){
            event.stopPropagation();
            $("html").click(function(){
                $thisPopOver.popover('hide');
            });
        });
    }
});

Hope this helps!

foxybagga
  • 4,184
  • 2
  • 34
  • 31
0

If you're trying to use twitter bootstrap popover with pjax, this worked for me:

App.Utils.Popover = {

  enableAll: function() {
    $('.pk-popover').popover(
      {
        trigger: 'click',
        html : true,
        container: 'body',
        placement: 'right',
      }
    );
  },

  bindDocumentClickEvent: function(documentObj) {
    $(documentObj).click(function(event) {
      if( !$(event.target).hasClass('pk-popover') ) {
        $('.pk-popover').popover('hide');
      }
    });
  }

};

$(document).on('ready pjax:end', function() {
  App.Utils.Popover.enableAll();
  App.Utils.Popover.bindDocumentClickEvent(this);
});
keruilin
  • 16,782
  • 34
  • 108
  • 175
0

@RayOnAir, I have same issue with previous solutions. I come close to @RayOnAir solution too. One thing that improved is close already opened popover when click on other popover marker. So my code is:

var clicked_popover_marker = null;
var popover_marker = '#pricing i';

$(popover_marker).popover({
  html: true,
  trigger: 'manual'
}).click(function (e) {
  clicked_popover_marker = this;

  $(popover_marker).not(clicked_popover_marker).popover('hide');
  $(clicked_popover_marker).popover('toggle');
});

$(document).click(function (e) {
  if (e.target != clicked_popover_marker) {
    $(popover_marker).popover('hide');
    clicked_popover_marker = null;
  }
});
0

I found this to be a modified solution of pbaron's suggestion above, because his solution activated the popover('hide') on all elements with class 'popup-marker'. However, when you're using popover() for html content instead of the data-content, as I'm doing below, any clicks inside that html popup actually activate the popover('hide'), which promptly closes the window. This method below iterates through each .popup-marker element and discovers first if the parent is related to the .popup-marker's id that was clicked, and if so then does not hide it. All other divs are hidden...

        $(function(){
            $('html').click(function(e) {
                // this is my departure from pbaron's code above
                // $('.popup-marker').popover('hide');
                $('.popup-marker').each(function() {
                    if ($(e.target).parents().children('.popup-marker').attr('id')!=($(this).attr('id'))) {
                        $(this).popover('hide');
                    }
                });
            });

            $('.popup-marker').popover({
                html: true,
                // this is where I'm setting the html for content from a nearby hidden div with id="html-"+clicked_div_id
                content: function() { return $('#html-'+$(this).attr('id')).html(); },
                trigger: 'manual'
            }).click(function(e) {
                $(this).popover('toggle');
                e.stopPropagation();
            });
        });
David
  • 446
  • 1
  • 7
  • 18
0

I came up with this:

My scenario included more popovers on the same page, and hiding them just made them invisible and because of that, clicking on items behind the popover was not possible. The idea is to mark the specific popover-link as 'active' and then you can simply 'toggle' the active popover. Doing so will close the popover completely.

$('.popover-link').popover({ html : true, container: 'body' })

$('.popover-link').popover().on 'shown.bs.popover', ->
  $(this).addClass('toggled')

$('.popover-link').popover().on 'hidden.bs.popover', ->
  $(this).removeClass('toggled')

$("body").on "click", (e) ->
  $openedPopoverLink = $(".popover-link.toggled")
  if $openedPopoverLink.has(e.target).length == 0
    $openedPopoverLink.popover "toggle"
    $openedPopoverLink.removeClass "toggled"
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
Adi Nistor
  • 112
  • 1
  • 6
0

I was trying to make a simple solution for a simple issue. Above posts are good but so complicated for a simple issue. So i made a simple thing. Just added a close button. Its perfect for me.

            $(".popover-link").click(function(){
                $(".mypopover").hide();
                $(this).parent().find(".mypopover").show();
        })
        $('.close').click(function(){
    $(this).parents('.mypopover').css('display','none');
});



          <div class="popover-content">
        <i class="fa fa-times close"></i>
    <h3 class="popover-title">Title here</h3>
your other content here
        </div>


   .popover-content {
    position:relative;
    }
    .close {
        position:absolute;
        color:#CCC;
        right:5px;
        top:5px;
        cursor:pointer;
    }
Mohammad Kashif
  • 93
  • 1
  • 1
  • 10
0

I like this, simple yet effective..

var openPopup;

$('[data-toggle="popover"]').on('click',function(){
    if(openPopup){
        $(openPopup).popover('hide');

    }
    openPopup=this;
});
gstarr
  • 1
  • 1
0

Add btn-popover class to your popover button/link that opens the popover. This code will close the popovers when clicking outside of it.

$('body').on('click', function(event) {
  if (!$(event.target).closest('.btn-popover, .popover').length) {
    $('.popover').popover('hide');
  }
});
Tobias Mühl
  • 1,788
  • 1
  • 18
  • 30
0

An even easier solution, just iterate through all popovers and hide if not this.

$(document).on('click', '.popup-marker', function() {
    $(this).popover('toggle')
})

$(document).bind('click touchstart', function(e) {
    var target = $(e.target)[0];
    $('.popup-marker').each(function () {
        // hide any open popovers except for the one we've clicked
        if (!$(this).is(target)) {
            $(this).popover('hide');
        }
    });
});
Tunaki
  • 132,869
  • 46
  • 340
  • 423
inostia
  • 7,777
  • 3
  • 30
  • 33
0
$('.popForm').popover();

$('.conteneurPopForm').on("click",".fermePopover",function(){
    $(".popForm").trigger("click");
});

To be clear, just trigger the popover

poete
  • 21
  • 2
0

This should work in Bootstrap 4:

$("#my-popover-trigger").popover({
  template: '<div class="popover my-popover-content" role="tooltip"><div class="arrow"></div><div class="popover-body"></div></div>',
  trigger: "manual"
})

$(document).click(function(e) {
  if ($(e.target).closest($("#my-popover-trigger")).length > 0) {
    $("#my-popover-trigger").popover("toggle")
  } else if (!$(e.target).closest($(".my-popover-content")).length > 0) {
    $("#my-popover-trigger").popover("hide")
  }
})

Explanation:

  • The first section inits the popover as per the docs: https://getbootstrap.com/docs/4.0/components/popovers/
  • The first "if" in the second section checks whether the clicked element is a descendant of #my-popover-trigger. If that is true, it toggles the popover (it handles the click on the trigger).
  • The second "if" in the second section checks whether the clicked element is a descendant of the popover content class which was defined in the init template. If it is not this means that the click was not inside the popover content, and the popover can be hidden.
Bart Blast
  • 959
  • 6
  • 6
-1

Try data-trigger="focus" instead of "click".

This solved the problem for me.

Hannes
  • 109
  • 2
-3
jQuery(':not(.popup-marker)').once().click(function(){
   jQuery('.popup-marker').hide(); 
});
everconfusedGuy
  • 2,709
  • 27
  • 43
  • could you provide a fiddle for this? I can't get your example working... thanks – Houman Sep 08 '12 at 23:22
  • 2
    So, err... not to be too harsh, but this is an *awful* solution. First: it binds an event listener to *every element in the page*. Second: it doesn't call the `.popover('hide')` method, which may lead to surprising things. Third: it will only work once. – David Wolever Jan 08 '14 at 22:11