9

Example 2D array:

var arr = [
  ["Mike", "Cane", 23],
  ["Jeff", "Meyers", 46],
  ["Thomas", "Bush", 67]
]

How do I copy a 2D array to the clipboard to then paste it in an excel spreadsheet? The rows and columns should be preserved as it is in the array. It should work the same way as if I would mark a range of cells in excel and then paste it back in.

oemera
  • 3,223
  • 1
  • 19
  • 33

4 Answers4

7

It's pretty easy, you just have to add a tab character \t to separate columns and a new line \n to seperate rows.

Use this code:

const excelData = arr
  .map(lines => lines.join("\t"))
  .join("\n");

const arr = [
  ["Mike", "Cane", 23],
  ["Jeff", "Meyers", 46],
  ["Thomas", "Bush", 67]
];

document.getElementById('convert').addEventListener('click', () => {
  const excelData = arr
    .map(lines => lines.join("\t"))
    .join("\n");
 
  document.getElementById('excel').textContent = excelData;
});
<textarea id="excel" cols="30" rows="6"></textarea><br>
<button id="convert">Make Excel Clipboard data</button>

Run code snipet, hit the button and copy paste text to Excel to test it out.

Christos Lytras
  • 36,310
  • 4
  • 80
  • 113
  • I ended up combining your and @Niklas E. answer. Your mapping from 2D-Array to String is way simplier, but I needed a solution to copy the array directly from code, after hitting ctrl+c. Your solution works perfectly fine, but requires and extra step and a "throw away" textarea in my case. Thank you! – oemera Mar 16 '20 at 08:42
  • I didn't thought the "copy to clipboard" functionality was important, you can find plenty of those answers in Stackoverflow Q/A easily, but it doesn't matter. @Niklas answers adds unneeded complexity but it does the job. – Christos Lytras Mar 16 '20 at 10:16
  • The complexity is definitely not "unneeded". My solution removes line breaks and tabs from each cell text, because otherwise you would run in some trouble, but I have to agree... using `Array#map` and `Array#join` may be nicer to look at. Should I edit my answer? – Niklas E. Mar 16 '20 at 11:30
  • @NiklasE.it's not nicer to just *"look at"*, it makes the code much more simple. And with *unneeded complexity* I am not refering to the cleaning using `/[\n\t]+/g` regexp, but to the loops. Your code is completely acceptable. `for` loops are of course valid and acceptable, I just point out it can be done in a more simple way in Javascript. You don't have to edit it, no, it's totally fine. – Christos Lytras Mar 16 '20 at 11:48
  • This is very simple and neat. Thank you for this solution. How can we add color formatting to this solution? As if I want the first row to be in red color and rest all rows can be as it is? Does anyone know the raw code for excel to render the color? – roronoa Aug 11 '20 at 11:44
  • thank you so much! BTW, you misspelled "separate" – Geoff Hom Dec 06 '20 at 06:50
  • 1
    @GeoffHom you're welcome and thanks for the correction. I have edited my answer and corrected the typo. You can also edit Q/A and correct any typos/errors you may find. – Christos Lytras Dec 06 '20 at 16:25
  • @ChristosLytras: Thanks for the info! I'm not used to using SO except to read answers. – Geoff Hom Dec 08 '20 at 06:00
4

This solution works amazing. It uses (CSV like) line breaks for a new row and tab for a new cell. Pasting text like this in an Excel, OpenOffice / LibreOffice Calc spreadsheet, it will detect it as multiple cells. It also works with Google Docs.

function copy2DToClipboard(array) {
  var csv = '', row, cell;
  for (row = 0; row < array.length; row++) {
    for (cell = 0; cell < array[row].length; cell++) {
      csv += (array[row][cell]+'').replace(/[\n\t]+/g, ' ');
      if (cell+1 < array[row].length) csv += '\t';
    }
    if (row+1 < array.length) csv += '\n';
  }
  copyTextToClipboard(csv);
}

// copied from https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
function fallbackCopyTextToClipboard(text) {
  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';
    // console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    // console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    console.error('Async: Could not copy text: ', err);
  });
}

Test:

function onTest() {
  const arr = [
    ["Mike", "Cane", 23],
    ["Jeff", "Meyers", 46],
    ["Thomas", "Bush", 67]
  ];
  copy2DToClipboard(arr);
  document.getElementById('test').innerText = 'Copied!';
}

function copy2DToClipboard(array) {
  var csv = '', row, cell;
  for (row = 0; row < array.length; row++) {
    for (cell = 0; cell < array[row].length; cell++) {
      csv += (array[row][cell]+'').replace(/[\n\t]+/g, ' ');
      if (cell+1 < array[row].length) csv += '\t';
    }
    if (row+1 < array.length) csv += '\n';
  }
  copyTextToClipboard(csv);
}

// copied from https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
function fallbackCopyTextToClipboard(text) {
  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';
    // console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    // console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    console.error('Async: Could not copy text: ', err);
  });
}
<button onclick="onTest()" id="test">Copy to clipboard.</button>

Edit:

This solution does not support cells with internal line breaks or tabs. Non-ascii unicodes can cause problems with some spreadsheet programs.

See also How do I copy to the clipboard in JavaScript?

Niklas E.
  • 1,848
  • 4
  • 13
  • 25
  • Thanks, this works just as I wanted to! Since I can use ES6+ the convertion from 2D-Array to String can be simplified, as @Christos Lytras has shown. – oemera Mar 16 '20 at 08:43
  • @oemera Ok, so I'd like to edit my answer for other users, that might see your question, to get an easier ES6+ solution (if that's ok with you). But I'd like to keep the `.replace(/[\n\t]+/g, ' ')`. I think this part is very important. – Niklas E. Mar 16 '20 at 11:45
0

I wanted to mention that there is now a simpler method to do the copying to the clipboard - you no longer need to create a textarea just so you can copy the data.

This example uses @christos-lytra's array mapping.

  const arr = [
    ['Mike', 'Cane', 23],
    ['Jeff', 'Meyers', 46],
    ['Thomas', 'Bush', 67],
  ];

  const excelData = arr.map(lines => lines.join('\t')).join('\n');

  navigator.clipboard.writeText(excelData);
Stephen Sisk
  • 155
  • 1
  • 11
-1

You have to save your array as JSON file then you can import to your JSON data to the excel sheet. Follow the below steps to import different forms of data to the excel sheet.

https://support.office.com/en-us/article/import-data-from-external-data-sources-power-query-be4330b3-5356-486c-a168-b68e9e616f5a

  • 1
    Unfortunately this is not an option. The process should be very quick and straight forward. Also the contents of the array are mostly very small. Saving and importing a JSON would just be too much of an effort. Yet this js still good to know, thanks. – oemera Mar 15 '20 at 22:40