Search code examples
javascripthtmlbootstrap-5bootstrap-popover

How I can display a dynamic popover with content upon value Copy?


I am trying to copy a value into clipboard:

/**
 * If not direct clipboard manipulation supported from browser, use a alternate approach
 * It is used upon copyTextToClipboard function.
 *
 * Function was seen in: https://stackoverflow.com/a/30810322/4706711
 *
 * @param {String} text
 */
function fallbackCopyTextToClipboard(text, callback) {
  var textArea = document.createElement("textarea");
  textArea.value = text;

  // Avoid scrolling to bottom
  textArea.style.top = "0";
  textArea.style.left = "0";
  textArea.style.position = "fixed";

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    if (successful) {
      callback(null, text);
    } else {
      callback("Usucessfull copying of the value", text);
    }
    console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    callback(err, text);
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}

/**
 * Copy text into clipboard.
 *
 * Function from: https://stackoverflow.com/a/30810322/4706711
 *
 * @param {String} text
 */
function copyTextToClipboard(text, callback) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    callback(null, text);
    console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    callback(err, text);
    console.error('Async: Could not copy text: ', err);
  });
}

$(document).ready(() => {

  $(".btn-copy").on("click", (e) => {
    const element = e.target;
    const text = $(element).data('val');

    copyTextToClipboard(text, (err, text) => {
      alert(`Copied value ${text}`)
      //Display a popover here
    });
  });
})
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>


<button class="btn btn-primary btn-copy" data-val="Copy">
  Copy Value
</button>

But In my case Instead of alert I want to display a bootstrap5.3 Popover once copied. How I can do that? I want the popover to be displayed dynamically with a dynamic content. Is there a way to do this?

The bootstrap version is 5.3.


Solution

  • In order to acheive that you need to render the popover as follows:

    /**
     * If not direct clipboard manipulation supported from browser, use a alternate approach
     * It is used upon copyTextToClipboard function.
     *
     * Function was seen in: https://stackoverflow.com/a/30810322/4706711
     *
     * @param {String} text
     */
    function fallbackCopyTextToClipboard(text, callback) {
      var textArea = document.createElement("textarea");
      textArea.value = text;
    
      // Avoid scrolling to bottom
      textArea.style.top = "0";
      textArea.style.left = "0";
      textArea.style.position = "fixed";
    
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
    
      try {
        var successful = document.execCommand('copy');
        var msg = successful ? 'successful' : 'unsuccessful';
        if (successful) {
          callback(null, text);
        } else {
          callback("Usucessfull copying of the value", text);
        }
        console.log('Fallback: Copying text command was ' + msg);
      } catch (err) {
        callback(err, text);
        console.error('Fallback: Oops, unable to copy', err);
      }
    
      document.body.removeChild(textArea);
    }
    
    /**
     * Copy text into clipboard.
     *
     * Function from: https://stackoverflow.com/a/30810322/4706711
     *
     * @param {String} text
     */
    function copyTextToClipboard(text, callback) {
      if (!navigator.clipboard) {
        fallbackCopyTextToClipboard(text);
        return;
      }
      navigator.clipboard.writeText(text).then(function() {
        callback(null, text);
        console.log('Async: Copying to clipboard was successful!');
      }, function(err) {
        callback(err, text);
        console.error('Async: Could not copy text: ', err);
      });
    }
    
    $(document).ready(() => {
    
      $(".btn-copy").on("click", (e) => {
        const element = e.target;
        const text = $(element).data('val');
    
        copyTextToClipboard(text, (err, text) => {
          const popover = new bootstrap.Popover(element, {
            content: `Copied value ${text}`,
            delay: {
              "hide": 500
            },
            'placement': "bottom"
          });
    
          popover.show();
          setTimeout(() => {
            popover.hide()
          }, 1000);
        });
      });
    })
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
    
    
    <button class="btn btn-primary btn-copy" data-val="Copy">
      Copy Value
    </button>

    Pay attetnion into this section in code above:

     const popover = new bootstrap.Popover(element, {
            content: `Copied value ${text}`,
            'placement': "bottom"
          });
    
          popover.show();
          setTimeout(() => {
            popover.hide()
          }, 1000);
    

    What I do is I place the popover's content into content setting whereas I use setTimeout and its callback to hide it.