web-dev-qa-db-fra.com

Comment repositionner un Popover Bootstrap après une insertion de contenu dynamique?

Ainsi, chaque fois que je charge un Bootstrap Popover avec une option content vide et que je l'insère de manière dynamique, le popover perd sa position correcte.

Par exemple:

$('td.chartSection').each(function () {
    var $thisElem = $(this);
    $thisElem.popover({
        placement: 'top',
        trigger: 'hover',
        html: true,
        container: $thisElem,
        delay: {
            hide: 500
        },
        content: ' '
    });
});

//After popup is shown, run this event
$('td.chartSection').on('shown.bs.popover', function () {
    var $largeChart = $(this).find('.popover .popover-content');

    //Insert some dummy content
    $largeChart.html("dfjhgqrgf regqef  f wrgb wrbgqwtgtrg <br /> wfghjqerghqreg fbvwqbtwfbvfgb <br />efgwetrg");
});

Ma question:

Existe-t-il une méthode permettant de recalculer la position de popovers telle que $('td.chartSection').popover('recalculate').

Ou existe-t-il un autre moyen de repositionner le popover sans le faire manuellement avec les styles CSS?

WORKING DEMO

18
Fizzix

Non, il n'y a pas de recalcul et il n'y a vraiment pas de moyen facile de le faire. Cela dit, vous pouvez injecter dynamiquement les popovers de cette façon:

$('td.chartSection').on('mouseenter', function() {
    var myPopOverContent = 'This is some static content, but could easily be some dynamically obtained data.';
    $(this).data('container', 'body');
    $(this).data('toggle', 'popover');
    $(this).data('placement', 'top');
    $(this).data('content', myPopOverContent);
    $(this).popover('show');
});

$('td.chartSection').on('mouseout', function() {
    $(this).popover('hide');
});

Il suffit de remplacer tous vos js dans votre violon avec ce qui précède et de le vérifier ...

7
jme11

En utilisant Bootstrap v3.3.7:

Vous pouvez étendre le constructeur Popover pour prendre en charge une fonction de repositionnement. Vous pouvez placer ce script ci-dessous à l'endroit où vous chargez bootstrap.

JSFiddle Demo

<script src="bootstrap.js"></script>
<script type="text/javascript">
$(function () {
    $.fn.popover.Constructor.prototype.reposition = function () {
        var $tip = this.tip()
        var autoPlace = true

        var placement = typeof this.options.placement === 'function' ? this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement

        var pos = this.getPosition()
        var actualWidth = $tip[0].offsetWidth
        var actualHeight = $tip[0].offsetHeight

        if (autoPlace) {
            var orgPlacement = placement
            var viewportDim = this.getPosition(this.$viewport)

            placement = placement === 'bottom' &&
                pos.bottom + actualHeight > viewportDim.bottom ? 'top' : placement === 'top' &&
                pos.top - actualHeight < viewportDim.top ? 'bottom' : placement === 'right' &&
                pos.right + actualWidth > viewportDim.width ? 'left' : placement === 'left' &&
                pos.left - actualWidth < viewportDim.left ? 'right' : placement

            $tip
                .removeClass(orgPlacement)
                .addClass(placement)
        }

        var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)

        this.applyPlacement(calculatedOffset, placement)
    }
})
</script>

Puis, dans votre script, chaque fois que vous devez repositionner votre info-bulle après avoir inséré du contenu. Vous pouvez simplement appeler:

$element.popover('reposition')
26
AlexCheuk

Je viens d'appeler

button.popover('show');

Et ça le repositionne. 

7
DigitalMC

J'ai eu une situation similaire où j'avais un popover qui contenait déjà du HTML (un spinner de chargement) et je changeais le contenu quand un appel ajax est revenu. Dans ma fonction de rappel ajax, c’était le code que j’avais utilisé pour changer le positionnement, de sorte qu’il restait centré:

var originalHeight = $(popover).height();

$(popover).find('.popover-content').html(data);

var newHeight = $(popover).height();
var top = parseFloat($(popover).css('top'));
var changeInHeight = newHeight - originalHeight;

$(popover).css({ top: top - (changeInHeight / 2) });
4
Tim

J'ai utilisé ce code pour ajuster la hauteur du popover lorsqu'il est déjà chargé dans la page:

   var popover = $(this).closest('.popover');
   var sender = popover.prev();
   var adjustment = (sender.position().top - popover.height()) + 15;
   popover.css({ top: adjustment });

Variable sender est la cible depuis laquelle le popover est centré.

4
muchacho

Si la position du popover est "haut" (comme dans la question), vous pouvez simplement ajuster son positionnement absolu à partir du haut de la page.

J'ai créé une fonction permettant de calculer la hauteur du popover, puis de la déplacer vers le haut de la page en fonction de sa hauteur.

function adjustPopoverHeight($popoverElement) {     
    var height = $popoverElement.height();
    var adjustment = 0 - height - 4;
    $popoverElement.css({ top: adjustment });
}

et utiliser avec une requête ajax pour obtenir des données:

 $.ajax({
    type: 'GET',
    url: url,
    contentType: 'application/json; charset=utf-8',
    dataType: 'json'
}).done(function(dat) { 
    //set the popover content to whatever you like

    //adjust height of popover
    var $popoverElement = $('.popover');
    adjustPopoverHeight($popoverElement);
})
1
Alex

J'ai pris le concept de la réponse de jme11 et mis à jour pour Bootstrap 3.3.2+

$('button')
  .popover({
    trigger: 'manual',
    html: true,
    container: 'body',
  })
  .click(function() {
    var $this = $(this);
    var popover_obj = $this.data('bs.popover');
    if (popover_obj.tip().hasClass('in')) {
      popover_obj.hide();
    } else {
      var opts = popover_obj.options;
      opts.content = $('<div/>').text('hello world');
      popover_obj.init('popover', $this, opts);
      popover_obj.show();
    }
  })
;

Il existe une méthode appelée setContent sur l'objet popover, mais pour une raison quelconque, cela ne fonctionnait pas pour moi. Si vous souhaitez essayer, cela ressemblerait à ceci:

popover_obj.setContent($('<div/>').text('hello world'));
0
Alex S

ceci est inspiré par la réponse de @AlexCheuk ci-dessus, mais j'avais besoin d'une solution utilisant Bootstrap 2 . De plus, dans mon projet, je n'avais pas besoin de changer le placement des popovers, alors je l'ai éliminé.

$(function() {
    $.fn.popover.Constructor.prototype.reposition = function () {
        console.log('popover reposition is called');
        var $tip = this.tip();

        var placement = typeof this.options.placement === 'function' ? this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement;

        var pos = this.getPosition();
        var actualWidth = $tip[0].offsetWidth;
        var actualHeight = $tip[0].offsetHeight;

        function getCalculatedOffset (placement, pos, actualWidth, actualHeight) {
            return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
                   placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
                   placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
                /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width };
        }

        var calculatedOffset = getCalculatedOffset(placement, pos, actualWidth, actualHeight);

        this.applyPlacement(calculatedOffset, placement);
        console.log(this);
    };
});

Pour l'appeler:

$element.popover('reposition')
0
Maria Blair