skip to Main Content

I’m trying to load a bootstrap 5 popover with dynamic content from an asynchronous function in which I have to wait for. I’m setting up my popover as so:

document.querySelectorAll('[data-bs-toggle="popover"]').forEach(function (popover) {

    new bootstrap.Popover(popover, {
        content: function () {
            (async () => {

                var x = await SetPopoverContent();
                return x;

            })()
        }
    });   
});

I’m then going back to the database and retrieving my data inside SetPopoverContent():

async function SetPopoverContent(popOver) {
    
    let contentText = '';
    let data = await dotNetReference.invokeMethodAsync('GetChatToInfo', messageId);
    if (data != null && data != undefined) {
        var outerDiv = '<div></div>';
        ...
        
        contentText = outerDiv.innerHTML;
    }
    else {

        contentText = '<p>Loading</p>';
    }
    
    return contentText;
}

I can see my html string inside my popover content function but the content never appears in the popover. Am I doing something wrong with the async callback method?

2

Answers


  1. What I think this should work.

    if (data != null && data != undefined) {
        var outerDiv = '<div></div>';
        ...
        
        contentText.innerHTML = outerDiv;
    }
    else {
    
        contentText = '<p>Loading</p>';
    }
    
    Login or Signup to reply.
  2. It won’t work with async calls, you need to use .setContent method instead on popover instance (alternatively, you could create popover after async call, or set content to loading... and then use .setContent).

    So, get popover instance, then run your async method, and then assign new content:

    // assign popover instance for later use
    const pop = new bootstrap.Popover(popover);
    
    // or set 'loading' right away
    //const pop = new bootstrap.Popover(popover, {
    //  content: '<p>Loading</p>'
    //});
    
    
    (async() => {
    
        var x = await SetPopoverContent();
    
        // set new content
        pop.setContent({
            '.popover-body': x
        })
    
    })()
    

    demo:

    <!doctype html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
      <title>Bootstrap Example</title>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    </head>
    
    <body class="p-3 m-0 border-0 bd-example m-0 border-0">
    
    
    
      <button type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover">Click to toggle popover</button>
    
    
    
      <script>
      
        function dbCall() {
          return new Promise(r => {
            setTimeout(() => r('new data'), 1000);
          })
        }
    
        async function SetPopoverContent() {
    
          let data = await dbCall();
    
          return data;
        }
    
    
        document.querySelectorAll('[data-bs-toggle="popover"]').forEach(function(popover) {
    
          const pop = new bootstrap.Popover(popover, {
            content: 'Loading'
          });
    
          (async() => {
    
            var x = await SetPopoverContent();
    
            pop.setContent({
              '.popover-body': x
            })
          })();
    
        });
      </script>
    
    </body>
    
    </html>

    see example for setting content: Popovers – Methods – setContent example

    The setContent
    method accepts an object argument, where each
    property-key is a valid string selector within the
    popover template, and each related property-value can be
    string | element | function |
    null

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search