Search code examples
jquerybootstrap-popover

Bootstrap popover does not show


I am trying to use a BS popover, my first time. I need to use the same popover for multiple elements so content and title will be dynamic. I googled and viewed a bunch of suggestions and still can't get this to work. I can see when element (a Fontawsome icon) is clicked, the appropriate function is called to fetch the title and content, but having problems with the popover.

<label>
  Some Text
  <span>
    <i
      class='fas fa-question-circle descPopover'
      aria-hidden='true'
      data-bs-toggle='popover'
      data-bs-placement='top'
      data-bs-trigger="focus"
      data-html="true"
      data-content="<div id='descContainer'>Loading...</div>"
      title="Click for more info"
      onclick="showDescr('vpc')"
    ></i>
  </span>
</label>

<label>
  Some Other Text
  <span>
    <i
      class='fas fa-question-circle descPopover'
      aria-hidden='true'
      data-bs-toggle='popover'
      data-bs-placement='top'
      data-bs-trigger="focus"
      data-html="true"
      data-content="<div id='descContainer'>Loading...</div>"
      title="Click for more info"
      onclick="showDescr('vpc')"
    ></i>
  </span>
</label>
function showDescr(code) {
    var descr = 'some description fecthed from an array';
    var heading = 'some title fecthed from an array';
    $('.descPopover').data("title", heading);
    $('.descPopover').data("content", descr);
    $('.descPopover').popover('show');
}

$(document).ready(function () {
    $('[data-bs-toggle="popover"]').popover();  
        
    $('.descPopover').on('show.bs.popover', function (e) {
        var popover = $(this);
        var content = popover.data('content');
        var title = popover.data('title');
        $('#descContainer').html(content);
    });
    // ...
});

When the question mark icon is clicked, it shows a popover, with two titles, presumably one for each label, one above the other, ("Click for more info") and the text "Loading ..." and no way to close it.

I put a breakpoing on showDesc() and can see it gets called but on('show.bs.popover') doesn't.


Solution

  • Even though it's not quite clear, what your final goal is, here's a simple setup that will make both popovers work with the dynamic content:

    <label>
      Some Text
      <span>
        <i
          class='fas fa-question-circle descPopover'
          tabindex="0"
          aria-hidden='true'
          data-bs-toggle='popover'
          data-bs-placement='top'
          data-bs-trigger="focus"
          data-html="true"
          data-content="<div id='descContainer'>Loading...</div>"
          title="Click for more info"
          onclick="showDescr('vpc', this)"
        ></i>
      </span>
    </label>
    
    <label>
      Some Other Text
      <span>
        <i
          class='fas fa-question-circle descPopover'
          tabindex="0"
          aria-hidden='true'
          data-bs-toggle='popover'
          data-bs-placement='top'
          data-bs-trigger="focus"
          data-html="true"
          data-content="<div id='descContainer'>Loading...</div>"
          title="Click for more info"
          onclick="showDescr('vpc', this)"
        ></i>
      </span>
    </label>
    
      function showDescr(code, el) {
        var descr = 'some description fecthed from an array';
        var heading = 'some title fecthed from an array';
        $(el).attr("data-bs-title", heading);
        $(el).attr("data-bs-content", descr);
        $(el).popover('toggle');
      }
      $("[data-bs-trigger='focus']").on("blur", e =>{
        $(e.target).popover("hide");
      })
    

    function showDescr(code, el) {
        var descr = 'some description fecthed from an array ' + Math.random().toFixed(2);
        var heading = 'some title fecthed from an array '  + Math.random().toFixed(2);
        $(el).attr("data-bs-title", heading);
        $(el).attr("data-bs-content", descr);
        $(el).popover('toggle');
      }
     $("[data-bs-trigger='focus']").on("blur", e =>{
        $(e.target).popover("hide");
      })
    <script
      src="https://code.jquery.com/jquery-3.7.1.min.js"
      integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
      crossorigin="anonymous"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" integrity="sha512-5Hs3dF2AEPkpNAR7UiOHba+lRSJNeM2ECkwxUIxC1Q/FLycGTbNapWXB4tP889k5T5Ju8fs4b1P5z/iB4nMfSQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    
    <label>
      Some Text
      <span>
        <i
          class='fas fa-question-circle descPopover'
          tabindex="0"
          aria-hidden='true'
          data-bs-toggle='popover'
          data-bs-placement='top'
          data-bs-trigger="focus"
          data-html="true"
          data-content="<div id='descContainer'>Loading...</div>"
          title="Click for more info"
          onclick="showDescr('vpc', this)"
        ></i>
      </span>
    </label>
    
    <label>
      Some Other Text
      <span>
        <i
          class='fas fa-question-circle descPopover'
          tabindex="0"
          aria-hidden='true'
          data-bs-toggle='popover'
          data-bs-placement='top'
          data-bs-trigger="focus"
          data-html="true"
          data-content="<div id='descContainer'>Loading...</div>"
          title="Click for more info"
          onclick="showDescr('vpc', this)"
        ></i>
      </span>
    </label>

    As you see, I am passing a second argument to the onclick handler, so that for each element, the handler has access to the element that triggered the call.

    showDescr('vpc') => showDescr('vpc', this)

    I have also switched to $().attr to make this work, along with switching over to toggle instead of show so that the handler automatically hides/shows the element. Otherwise, you'll get a flickering issue, when the code tries to show an already open popover.

    I've also included a working demo. Open and try the snippet.

    Update: in order for the popover to toggle on 'blur' (while the user clicks on another part of the DOM), I've added a required tabindex on the 2 elements and an onblur handler to hide the popovers.