0

I have this function called copyToClipboard(). This takes a parameter called element. This function copies the content of a element by locating its id, selecting and copying the contents.

For instance:

JS

/*
*  Copy to clipboard fn
*/
function copyToClipboard(element) {
  var $temp = $("<input>");  
  $("body").append($temp);
  $temp.val($(element).text()).select();
  document.execCommand("copy");
  var $tempval = $temp.val($(element).text());
  $temp.remove();  

  var $notif = $("<p>");
  $notif.attr("class","notif");
  $("body").append($notif);
  $notif.html('Copied content to clipboard!');
  setTimeout(function() {
      $notif.fadeOut();
      $notif.promise().done(function(){
        this.remove();
      });
  }, 400);
}

HTML:

<p id="p1">content of #p1</p>
<p> not me tho </p>
<p id="p2">content of #p2</p>   
<button onclick="copyToClipboard('#p1')">Copy P1</button>
<button onclick="copyToClipboard('#p2')">Copy P2</button>

I am trying to improve this into a function which generates the buttons dynamically.

My approach so far where I integrated the above function into a new function, iterating over the elements found by ID/Class (IDs in this example),vb generating buttons with the onclick function container the iterated value as a parameter/argument.

/*
* generate copy buttons fn
*/
function generateCopyButtons() {

  var links = document.getElementById('links').getElementsByTagName('p');
      for (var i = 0; i < links.length; i++) {
          var $link = links[i];
          var thisId = $($link).attr('id');     
              if( thisId && thisId !== "null" && thisId !== "undefined" ){                  
                  var $button = document.createElement('button'); // btn
                  $button.innerHTML = 'Copy ' + thisId; //btn text
                  var element = '#' + thisId; // # + id 
                // console.log(element); // works like i want, #p1, #p2

                //how do i pass the element into this function??
                $button.onclick = function(element) {
                    var $temp = $("<input>");                    
                    $temp.val($(element).text()).select();
                    document.execCommand("copy");
                    var $tempval = $temp.val($(element).text());
                    $("body").append($temp);
                    $temp.remove();

                var $notif = $("<p>");
                $notif.attr("class","notif");
                $("body").append($notif);
                $notif.html('Copied content to clipboard!');
                setTimeout(function() {
                    $notif.fadeOut();
                    $notif.promise().done(function(){
                      $notif.remove();
                    });
                }, 400);
            };
              $($link).prepend($button);              
              // $($thisHashId).remove();
          }
}

}
$(document).ready(function(){
  generateCopyButtons();
});

Right now it doesn't show errors and it doesn't work. Using the previous buttons works fine.

jsfiddle demonstrating problem

2 Answers 2

2

One solution include 2 steps.

First get all <p> nodes inside the #links and filter out those with no id.

var pNodes = document.querySelectorAll('#links p[id^="p"]');
pNodes.forEach(function(element){
    var button = document.createElement('button');

    [...] //add button text, etc..

    button.setAttribute('data-p',element.getAttribute('id') );
    element.insertAdjacentHtml('afterend', button);
});

A great way to remove unnecessary code is to use a delegate. When you click any node in the document, by default the event is propagated upwards, this means that <button> elements click can be listened from it's parent #links node, this will reduce the amount of code by removing the for loop.

var node = document.getElementById("links");
node.addEventListener("click", function(e) {
    if(e.target && e.target.nodeName == "P") {
        //click event target is a <button> node
        //here e.target is the <button> DOM node
        //use e.target.getAttribute('data-p') to retrieve the <p>'s ID
    }
}

This solves the need to attach a listener on every button, button generation can be handled in another script/function I'm not sure if it will work on all browsers (IE)

Sign up to request clarification or add additional context in comments.

8 Comments

thanks i will update my answer with this code later. IE compat is not neccesary thanks. Still looking for a option to pass the dynamic argument into the onclick function.
i'm not sure where this helps me with generating the arguments, but its a nicer way of writing the loop for sure.
what kind of arguments are you looking for? have you considered to insert data tag inside the generated p element?
You could Store all the <p> tags in an array, filter those without an id, and foreach p create a sibling button that got the id parameter inside a data-p-id or something, then watch using e.target.nodeName == "BUTTON"
I 'm not trying to generate the p's. What i want is to generate buttons, prepended or appended to the p's (if they have a ID), set this ID ( + # ) as argument of the onclick for each button-> e.g. <p id="p1">...</p> becomes <p id="p1">...</p><button onclick="copyToClipboard('#p1')">...</button> Hope this makes sence
|
0

Thanks to @lookforangular is was able to update my code. first selecting all p nodes in the div#links in a foreach loop. This way the click event can be handeled in general instead of selecting single p nodes.

By setting the id as a data-p the click event can use the data-p value as dynamic argument to target the div you want to copy. Feel free to rewrite, use or update this function. Below the code is a link to a working fiddle demonstrating the effect. Small bonus a message notifies the user of this action.

 /*
  * generate copy buttons fn
  */
 function generateCopyButtons() {
   var pNodes = document.querySelectorAll('#links p[id^="p"]');
   pNodes.forEach(function(element) {
     var $button = document.createElement('button'); // btn       
     $button.innerHTML = 'Copy ' + element.id; //btn text
  // for this example we will set the value of data-p dynamically with the id so we have something to target. 
     $button.setAttribute('data-p', element.getAttribute('id'));
     element.prepend($button);

   $($button).on("click", function() {
     var $datap = '"#' + $($button).attr('data-p') + '"';
     //console.log($datap);
     var $temp = $("<input>");
     $("body").append($temp);
     $temp.val($(element).text()).select();
     document.execCommand("copy");
     $temp.remove();

     var $notif = $("<p>");
     $notif.attr("class", "notif");
     $("body").append($notif);
     $notif.html('Copied content to clipboard!');
     setTimeout(function() {
       $notif.fadeOut();
       $notif.promise().done(function() {
         this.remove();
       });
     }, 400);
   });

   });
 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.