Question

I am trying to create a menu using a sidebar with buttons, each one with an assigned popover containing the relevant data. Unfortunately, one of the popovers might contain an arbitrary number of rows and in some cases it might be partially outside the viewport.

See http://jsfiddle.net/bfd9f/1/ for an example of the issue (click the "Tasks" button)

I thought I could programmatically alter the popover's top to a defined value, when negative (i.e. outside the viewport) and to do this, I already managed to get a reference to the first div of the popover while listening to the show.bs.popover event. Unfortunately, I think due to the fact that it's not rendered yet, it appears to have a size of (23, 107) while it should be something like (300, xxx) and a position of (0, 0).

Is there a way to solve this issue? maybe rendering the popover offscreen first to measure it? if so, how would I do that?

Thanks

Was it helpful?

Solution

Fixed in the upcoming Bootstrap v3.2.0 I believe: http://jsfiddle.net/pkP77/1/

Courtesy of the new viewport feature introduced in https://github.com/twbs/bootstrap/pull/12328

OTHER TIPS

You can always override the top value of the popover using !important This might not be the best long term plan as it might interfere with future CSS changes

 .popover {
        width: 300px !important;
        top: 0px !important;
    }

http://jsfiddle.net/smurphy/x9hnk/

Update:

Going off of the event you mentioned this seems to work.

$('.btn-popover').on('shown.bs.popover', function (event) {
    //Set timeout to wait for popup div to redraw(animation)
    setTimeout(function(){
        if($('div.popover').css('top').charAt(0) === '-'){
             $('div.popover').css('top', '0px');
             var buttonTop = $(event.currentTarget).position().top;
             var buttonHeight = $(event.currentTarget).height();
             $('.popover.left>.arrow').css('top', buttonTop + (buttonHeight/2));
        }
    },100);
});

http://jsfiddle.net/smurphy/e6YaY/2/

This aligns the arrow with your button. enter image description here

For people struggling with popovers with changing/dynamic content falling outside of the viewport...

Create a function to check if part of an element is outside the viewport:

const isOutOfViewport = (el) => {
  /**
   * Your code which checks if an element is partly outside of the viewport
   * For instance: https://gomakethings.com/how-to-check-if-any-part-of-an-element-is-out-of-the-viewport-with-vanilla-js/
   */
}

Next create a ResizeObserver so we can watch any resizing events of the popover like this:

const popoverElResizeObserver = new ResizeObserver((entries) => {
    entries.forEach((item) => {
        let el = item.target
        if (isOutOfViewport(el)) {
            $(el).popover('update')
        }
    })
})

Then apply the observer on a popover when it gets inserted ("insert" event happens before "shown" event but after "show" event)

$(document)
    .on('inserted.bs.popover', (e) => {
        // This piece of code gets the connected popover (the "tip" is the popover element)
        let myPopover = $(e.target).data('bs.popover').tip
        popoverElResizeObserver.observe(myPopover)
    })

Now every time the popover gets resized (or created, or removed) and is partly outside the viewport, the .popover('update') gets triggered

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top