15

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

SirePi
  • 242
  • 1
  • 3
  • 11

3 Answers3

13

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

cvrebert
  • 9,075
  • 2
  • 38
  • 49
  • That's exactly what I need. I don't think 3.2 is out yet.. does it mean I have to grab the js from the fiddle? – SirePi May 15 '14 at 06:32
  • Sorry for the delay but I've been busy; I tried using the version linked but I had some issue, namely because in these days I changed from setting content via $(obj).html() to $(obj) directly. What happens is that the first time I get by popover correctly, but after closing it the $(obj) is erased from the dom and cannot be shown again. For now I managed by merging some lines from bootstrap 3.2 to 3.1.1 and it appears to be working correctly. Are you interested in seeing what I changed? – SirePi Jun 05 '14 at 12:57
  • 1
    how is it possible to use this in html ? I could not find any explanation in the docs. actually, the doc gives you the finger and tells you to: "Address these issues on your own as they arise." nice! – Michahell Jun 13 '16 at 15:51
  • Downvoted as it does not clearly give a solution to the problem and simply directs you to off site links that could break or change in future. – Andrew Sep 02 '19 at 09:18
3

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

Scott Murphy
  • 448
  • 2
  • 12
  • I already thought of that.. unfortunately it will affect all popovers (see the effect on the "User" button), while I would like to alter only those that go somehow outside the viewport (the same might happen on the bottom.. I don't know yet how many buttons I will have in the sidebar). – SirePi May 14 '14 at 12:47
  • Yes I did. I gave it another read in case I missed something but still it's not what I need. Even if you use a function, that function could only return one of the supported values for positioning the tooltip relative to the element triggering it. For me, there is no choice: it has to be left. – SirePi May 14 '14 at 13:13
  • _Comment to the update_: Yes, it was something I already explored as well.. it works but only after the popup has completed its animation; The effect is not too pretty to see. Anyway, it could work if I remove the fade animation; the arrow can be moved at the same time in case. At the moment I am trying to find the exact place in bootstrap's source where the content is assigned to the popover. The width is correct, but the height appears as -4. – SirePi May 14 '14 at 13:56
  • 1
    Here's an improved version which fixes the ugly jump and positions the arrow correctly: http://jsfiddle.net/e6YaY/11/ – user3374348 Jun 02 '15 at 08:37
0

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

Julesezaar
  • 2,658
  • 1
  • 21
  • 21