Murtuza Z
Murtuza Z

Reputation: 6017

Can not copy text into Clipboard - JavaScript

I am trying to copy csv based data (from SlickGrid), in to system clipboard. For small chunks of data it is working fine, but when I have large set of data it is unable to copy into system clipboard.

Here is the code use to perform copy:

copyTextToClipboard: function (text) {
    var textArea = document.createElement('textarea');

    // Hide textArea
    textArea.style.position = 'fixed';
    textArea.style.top = 0;
    textArea.style.left = 0;
    textArea.style.width = '2em';
    textArea.style.height = '2em';
    textArea.style.padding = 0;
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';
    textArea.style.background = 'transparent';

    textArea.value = text;
    document.body.appendChild(textArea);
    textArea.select();

    try {
        var successful = document.execCommand('copy');
        var msg = successful ? 'successful' : 'unsuccessful';
        console.log('Copying text command was ' + msg);
    } catch (err) {
        alert('Oops, unable to copy to clipboard');
    }

    document.body.removeChild(textArea);
}

When I pass large csv based text into function, I always get:

'Copying text command was unsuccessful'

Sample CSV based text passed into 'copyTextToClipboard' function which fails to copy in clipboard enter image description here

Another interesting thing here, is when I use Developer tool and step over each line it properly copies the same data into Clipboard.

Upvotes: 0

Views: 1939

Answers (1)

zer00ne
zer00ne

Reputation: 43880

The reason why it fails normally and in console it gives partial results is because the input is more than one line. Your function is made to accept a normal string without line breaks. I would assume before ES6 you'd have to insert the line breaks with a backslash \n+ manually or programmatically.

Assuming that you don't care about IE (see caniuse) ES6 Template Literals takes the humble String to a whole new level. The features used in the following demo are:

  // Conventional String
   var str = "These   words   are   3   spaces   apart"; 

  // Template Literal
   var tl = `These   words   are   3   spaces   apart`
   var x = 123;

  // Conventional String
   var str = "Height: " + x + "px";

  // Template Literal
   var tl = `Height: ${x}px`;
 // Conventional String
   var str = "\n+"
             "Multiple\n+"
             "lines\n";

 // Template Literal
   var tl = `
            Multiple
            lines


Basic Syntax

  • Wrap string in backticks: ` (top left corner of keyboard) instead of quotes: " or '

  • Wrap variables with ${} instead of "+ +"

  • Just use the enter key instead of \n+


Details are commented in demo

Plunker

Demo

textarea {
  width: 90%;
  min-height: 100px;
  margin: 10px;
  border: 2px solid black;
  font: inherit;
}

button {
  float: right;
  margin-right: 10%
}
<!DOCTYPE html>
<html>

<head>
  <style>
    body {
      font: 400 13px/1.428 Consolas;
    }
    /* This is just to make the console
    || display data that needs no horizontal 
    || scrolling to read.
    */
    
    .as-console {
      word-break: break-word;
    }
    
    button {
      margin-left: 18ch;
    }
  </style>
</head>

<body>
  <ol>
    <li>Enter text with line breaks.✎</li>
    <li>Click the <kbd>DONE</kbd> button</li>
    <li>Next do one of the following:
      <ul>
        <li>Open a text editor (like Notepad)</li>
        <div>OR</div>
        <li>Go to the auxiliary demo on this answer</li>
      </ul>
      <li>Paste into the text editor or the aux demo</li>
  </ol>
  <p>✎ or you can use a <a href='https://pastebin.com/VZ6Vk4py' target='_blank'>
delimited text file (CSV) of 26 columns and 1000 rows
</a> (right click and open new tab.)</p>

  <textarea id='TA'></textarea>
  <br/>
  <button>DONE</button>
  <br/>

  <script>
    // Reference the <textarea>
    var TA = document.getElementById('TA');

    /* Register #TA to the change event
    || After the user has typed in #TA
    || and then clicks elsewhere 
    || (like the inert <button>)... 
    */
    TA.addEventListener('change', function(e) {

      /* ... the callback function is invoked and
      || the value of the changed element
      || (i.e. e.target = #TA) is passed thru.
      */
      copyTextToClipboard(e.target.value);
    });

    // Define callback function
    function copyTextToClipboard(text) {

      // Create a <textarea>
      var textArea = document.createElement('textarea');
      // Hide new <textarea>
      textArea.style.opacity = 0;

      // Append new <textarea> to the <form>
      document.body.appendChild(textArea);

      /* Wrap the data in backticks:` 
      || (key is top left corner of keyboard)
      || and the variable of data in a dollar
      || sign and curly brackets: ${}
      || The data (a string), is now an 
      || ES6 template literal.
      */
      var str = `${text}`;

      // Assign the new <textArea> value to str
      textArea.value = str;

      /* .select() method gets the content of
      || new <textarea>
      */
      textArea.select();

      /* copy the selected text to the OS
      || clipboard.
      */
      document.execCommand('copy');

      console.log(str);
    }
  </script>
</body>

</html>

Auxiliary Demo

Paste Text from Demo Here

body {
  font: 400 13px/1.428 Consolas
}

textarea {
  width: 90%;
  min-height: 250px;
  margin: 10px;
  border: 2px solid black;
  font: inherit;
}
<textarea placeholder='Paste text in this textarea'></textarea>

Upvotes: 1

Related Questions