217

I am trying to implement an icon that when clicked will save a variable to the user's clipboard. I have currently tried several libraries and none of them have been able to do so.

How do I properly copy a variable to the user's clipboard in Angular 5?

Sangram Nandkhile
  • 17,634
  • 19
  • 82
  • 116
anonymous-dev
  • 2,356
  • 2
  • 11
  • 17
  • you can use [ngxyz-c2c](https://www.npmjs.com/package/ngxyz-c2c), there are multiple ways to do it. – Ankit Singh Dec 12 '19 at 21:24
  • 1
    If you're using Angular Material then version 9.0.0 (released Feb 6th, 2020) introduced the super easy to use [clipboard package](https://material.angular.io/cdk/clipboard/overview). See the Angular documentation and @Nabel's [answer](https://stackoverflow.com/a/60621480/245602). – George Hawkins Mar 22 '20 at 13:06

20 Answers20

367

Solution 1: Copy any text

HTML

<button (click)="copyMessage('This goes to Clipboard')" value="click to copy" >Copy this</button>

.ts file

copyMessage(val: string){
    const selBox = document.createElement('textarea');
    selBox.style.position = 'fixed';
    selBox.style.left = '0';
    selBox.style.top = '0';
    selBox.style.opacity = '0';
    selBox.value = val;
    document.body.appendChild(selBox);
    selBox.focus();
    selBox.select();
    document.execCommand('copy');
    document.body.removeChild(selBox);
  }

Solution 2: Copy from a TextBox

HTML

 <input type="text" value="User input Text to copy" #userinput>
      <button (click)="copyInputMessage(userinput)" value="click to copy" >Copy from Textbox</button>

.ts file

    /* To copy Text from Textbox */
  copyInputMessage(inputElement){
    inputElement.select();
    document.execCommand('copy');
    inputElement.setSelectionRange(0, 0);
  }

Demo Here


Solution 3: Import a 3rd party directive ngx-clipboard

<button class="btn btn-default" type="button" ngxClipboard [cbContent]="Text to be copied">copy</button>

Solution 4: Custom Directive

If you prefer using a custom directive, Check Dan Dohotaru's answer which is an elegant solution implemented using ClipboardEvent.


Solution 5: Angular Material

Angular material 9 + users can utilize the built-in clipboard feature to copy text. There are a few more customization available such as limiting the number of attempts to copy data.

Sangram Nandkhile
  • 17,634
  • 19
  • 82
  • 116
  • 1
    Great idea, but I copyied your 2nd solution and I keep getting `Cannot read property 'select' of undefined` in angular 6. Is this angular6-compatible? – slevin Jul 07 '18 at 14:43
  • 1
    @slevin I don't think it is related to angular version in any way. DId you add ` #userinput` to your input? – Sangram Nandkhile Jul 09 '18 at 01:28
  • 2
    @SangramNandkhile I checked again and again, but still the same error. This is my code ` ` Thanks – slevin Jul 09 '18 at 17:32
  • 1
    You can even remove the `position`, `left`, `top`, and `opacity`. and replace it with a `selBox.style.height = '0';` – Mendy Jul 18 '18 at 15:07
  • minor issue, should use const not let – Stephen DuMont Jul 25 '18 at 21:43
  • how to check if copied from ts ? – Charitha Goonewardena Aug 14 '18 at 11:41
  • @SangramNandkhile This method does not work for `focus trapped` elements. What is the solution for `focus trapped` elements? https://github.com/maxisam/ngx-clipboard/issues/152 – omurbek Aug 22 '18 at 07:38
  • I tried the solution 1, but document.executeCommand('copy') always returning false. any suggestion? – Tasnim Fabiha Dec 09 '18 at 07:49
  • worth showing that solution 1 html could be changed to: `` – somedirection Apr 23 '19 at 20:24
  • the cool part about solution 1 is that you can encapsulate it in an injectable service – Vee6 Oct 29 '19 at 10:58
  • `ngx-clipboard` has a separate method `ClipboardService.copy()`. So we can copy any text just in a template controller, without any things in html template. That's what I was looking for. Thank you! https://www.npmjs.com/package/ngx-clipboard – ame Nov 09 '20 at 15:09
  • 1
    You should NEVER access the DOM directly in angular. Make sure to [inject document](https://stackoverflow.com/questions/37521298/how-to-inject-document-in-service) the right way! – Jonathan Aug 09 '21 at 01:47
  • @Jonathan, works pretty well with injected `document` and a `ViewChild`, instead of inserting an element at runtime! :) – Guntram Mar 30 '22 at 16:13
99

I know this has already been highly voted in here by now, but I'd rather go for a custom directive approach and rely on the ClipboardEvent as @jockeisorby suggested, while also making sure the listener is correctly removed (same function needs to be provided for both the add and remove event listeners)

stackblitz demo

import { Directive, Input, Output, EventEmitter, HostListener } from "@angular/core";

@Directive({ selector: '[copy-clipboard]' })
export class CopyClipboardDirective {

  @Input("copy-clipboard")
  public payload: string;

  @Output("copied")
  public copied: EventEmitter<string> = new EventEmitter<string>();

  @HostListener("click", ["$event"])
  public onClick(event: MouseEvent): void {

    event.preventDefault();
    if (!this.payload)
      return;

    let listener = (e: ClipboardEvent) => {
      let clipboard = e.clipboardData || window["clipboardData"];
      clipboard.setData("text", this.payload.toString());
      e.preventDefault();

      this.copied.emit(this.payload);
    };

    document.addEventListener("copy", listener, false)
    document.execCommand("copy");
    document.removeEventListener("copy", listener, false);
  }
}

and then use it as such

<a role="button" [copy-clipboard]="'some stuff'" (copied)="notify($event)">
  <i class="fa fa-clipboard"></i>
  Copy
</a>

public notify(payload: string) {
   // Might want to notify the user that something has been pushed to the clipboard
   console.info(`'${payload}' has been copied to clipboard`);
}

Note: notice the window["clipboardData"] is needed for IE as it does not understand e.clipboardData

Dan Dohotaru
  • 2,809
  • 19
  • 15
75

I think this is a much more cleaner solution when copying text:

copyToClipboard(item) {
    document.addEventListener('copy', (e: ClipboardEvent) => {
      e.clipboardData.setData('text/plain', (item));
      e.preventDefault();
      document.removeEventListener('copy', null);
    });
    document.execCommand('copy');
  }

And then just call copyToClipboard on click event in html. (click)="copyToClipboard('texttocopy')".

MD. Khairul Basar
  • 4,976
  • 14
  • 41
  • 59
jockeisorby
  • 783
  • 5
  • 3
41

As of Angular Material v9, it now has a clipboard CDK

Clipboard | Angular Material

It can be used as simply as

<button [cdkCopyToClipboard]="This goes to Clipboard">Copy this</button>
Nabel
  • 1,767
  • 14
  • 23
28

Copy using angular cdk,

Module.ts

import {ClipboardModule} from '@angular/cdk/clipboard';

Programmatically copy a string: MyComponent.ts,

class MyComponent {
  constructor(private clipboard: Clipboard) {}

  copyHeroName() {
    this.clipboard.copy('Alphonso');
  }
}

Click an element to copy via HTML:

<button [cdkCopyToClipboard]="longText" [cdkCopyToClipboardAttempts]="2">Copy text</button>

Reference: https://material.angular.io/cdk/clipboard/overview

Chandrahasan
  • 1,991
  • 24
  • 26
  • 3
    This forces you to use Angular Material – edu Oct 16 '20 at 21:24
  • 1
    This worked so much better than the other ones. I had bugs in the other copy examples and I already had cdk imported. yay! – Omzig Oct 23 '20 at 22:03
  • 3
    @edu you don't necessarily need to install the whole ```@angular/material``` package, but just its peer dependency: ```@angular/cdk``` – Memphis May 12 '22 at 09:57
20

Modified version of jockeisorby's answer that fixes the event handler not being properly removed.

copyToClipboard(item): void {
    let listener = (e: ClipboardEvent) => {
        e.clipboardData.setData('text/plain', (item));
        e.preventDefault();
    };

    document.addEventListener('copy', listener);
    document.execCommand('copy');
    document.removeEventListener('copy', listener);
}
John
  • 1,186
  • 10
  • 9
  • 1
    Not working in Firefox. Error - `document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler` – OPTIMUS Sep 25 '19 at 12:48
15

You can achieve this using Angular modules:

navigator.clipboard.writeText('your text').then().catch(e => console.error(e));
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
7

It's simple bro

in .html file

<button (click)="copyMessage('This goes to Clipboard')" value="click to copy" >Copy this</button>

in .ts file

copyMessage(text: string) {
  navigator.clipboard.writeText(text).then().catch(e => console.log(e));
}
Learn More
  • 937
  • 1
  • 8
  • 8
5

For me document.execCommand('copy') was giving deprecated warning and the data I need to copy was inside <div> as textNode rather than <input> or <textarea>.

This is how I did it in Angular 7 (inspired by answers of @Anantharaman and @Codemaker):

<div id="myDiv"> &lt &nbsp This is the text to copy. &nbsp &gt </div>
<button (click)="copyToClipboard()" class="copy-btn"></button>
 copyToClipboard() {
    const content = (document.getElementById('myDiv') as HTMLElement).innerText;
    navigator['clipboard'].writeText(content).then().catch(e => console.error(e));

  }
}

Definitely not the best way, but it serves the purpose.

Gopal Mishra
  • 1,575
  • 1
  • 14
  • 17
  • Thank you. The other navigator.clipboard would throw an error, navigator['clipboard'] worked just fine. Best way to do it without having to upgrade the entire code base to latest Angular. – ScottN Aug 24 '22 at 23:56
2
// for copy the text
import { Clipboard } from "@angular/cdk/clipboard"; // first import this in .ts
 constructor(
    public clipboard: Clipboard
  ) { }   
 <button class="btn btn-success btn-block"(click) = "onCopy('some text')" > Copy< /button>

 onCopy(value) {
     this.clipboard.copy(value);
    }


 // for paste the copied text on button click :here is code
    
    <button class="btn btn-success btn-block"(click) = "onpaste()" > Paste < /button>
    
    onpaste() {
      navigator['clipboard'].readText().then(clipText => {
        console.log(clipText);
      });
    }
Keyur Patel
  • 59
  • 1
  • 5
  • 1
    Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you've made – Himanshi Thakur May 04 '21 at 06:00
1

Below method can be used for copying the message:-

export function copyTextAreaToClipBoard(message: string) {
  const cleanText = message.replace(/<\/?[^>]+(>|$)/g, '');
  const x = document.createElement('TEXTAREA') as HTMLTextAreaElement;
  x.value = cleanText;
  document.body.appendChild(x);
  x.select();
  document.execCommand('copy');
  document.body.removeChild(x);
}
Durgesh Pal
  • 695
  • 5
  • 13
1

The best way to do this in Angular and keep the code simple is to use this project.

https://www.npmjs.com/package/ngx-clipboard

    <fa-icon icon="copy" ngbTooltip="Copy to Clipboard" aria-hidden="true" 
    ngxClipboard [cbContent]="target value here" 
    (cbOnSuccess)="copied($event)"></fa-icon>
Rahul Basu
  • 11
  • 2
1

Much More Easier enter image description here

let textToCopy: string = `\nAccess Token: ${conn.accessToken} \nInstance Url: ${conn.instanceUrl} \nOrg ID: ${conn.userInfo.organizationId}`;
navigator.clipboard.writeText(textToCopy.trim());
avariant
  • 2,234
  • 5
  • 25
  • 33
0

First suggested solution works, we just need to change

selBox.value = val;

To

selBox.innerText = val;

i.e.,

HTML:

<button (click)="copyMessage('This goes to Clipboard')" value="click to copy" >Copy this</button>

.ts file:

copyMessage(val: string){
    const selBox = document.createElement('textarea');
    selBox.style.position = 'fixed';
    selBox.style.left = '0';
    selBox.style.top = '0';
    selBox.style.opacity = '0';
    selBox.innerText = val;
    document.body.appendChild(selBox);
    selBox.focus();
    selBox.select();
    document.execCommand('copy');
    document.body.removeChild(selBox);
  }
Sreeketh K
  • 21
  • 4
0

Found the simplest solution for myself with pure Angular and ViewChild.

import { Component, ViewChild } from '@angular/core';

@Component({
  selector: 'cbtest',
  template: `
    <input type="text" #inp/>
    <input type="button" (click)="copy ()" value="copy now"/>`
})

export class CbTestComponent
{
  @ViewChild ("inp") inp : any;

  copy ()
  {
    // this.inp.nativeElement.value = "blabla";  // you can set a value manually too

    this.inp.nativeElement.select ();   // select
    document.execCommand ("copy");      // copy
    this.inp.nativeElement.blur ();     // unselect
  }
}
chris01
  • 10,921
  • 9
  • 54
  • 93
0

Following Solution 1 of @Sangram's answer (and the comment from @Jonathan):

(In favor of "do not use plain document in angular" and "do not add HTML elements from code if you don't have to...)

// TS

@ViewChild('textarea') textarea: ElementRef;

constructor(@Inject(DOCUMENT) private document: Document) {}

public copyToClipboard(text): void {
  console.log(`> copyToClipboard(): copied "${text}"`);
  this.textarea.nativeElement.value = text;
  this.textarea.nativeElement.focus();
  this.textarea.nativeElement.select();
  this.document.execCommand('copy');
}
/* CSS */
.textarea-for-clipboard-copy {
  left: -10000;
  opacity: 0;
  position: fixed;
  top: -10000;
}
<!-- HTML -->
<textarea class="textarea-for-clipboard-copy" #textarea></textarea>
Guntram
  • 961
  • 14
  • 19
0

I don't understand all the complicated code and using libraries to do something so simple. just do this:

html:

<span (mousedown)="copyText()">{{text}}</span>

ts:

copyText() {
  navigator.clipboard.writeText(this.text);
}

that's it!

Rick
  • 1,710
  • 8
  • 17
0

A very simple answer - how to copy text to clipboard.

IN HTML

<input #copy><button (click)="copyToClipboard(copy.value)">Copy To Clipboard</button>

IN TS

copyToClipboard(text) {
// Create a temporary textarea element to hold the text
const textarea = document.createElement('textarea');
textarea.value = text;

// Append the textarea to the document
document.body.appendChild(textarea);

// Select the text in the textarea
textarea.select();

// Copy the selected text to the clipboard
document.execCommand('copy');

// Remove the textarea from the document
document.body.removeChild(textarea);

}

Here is the Stackblitz

https://stackblitz.com/edit/angular-copytexttoclipboard?file=README.md

-1

phoneNoAction = (mobile) => {
    $('.copy').on('click', () =>{
      navigator['clipboard'].writeText(mobile).then().catch(e =>            console.error(e));
    })
  }
<p style="cursor: pointer;"class="card-text" (click)="phoneNoAction(item.MobileNumb)">
{{item.MobileNumb}}</p>

<button class="copy">copy mobile number</button>
avariant
  • 2,234
  • 5
  • 25
  • 33
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 30 '23 at 08:37
  • Actually I'm new on this platform. Thank you for suggestion. I'll improve next time for sure. – Swati Dubey Apr 04 '23 at 07:50
-2
copyCurl(val: string){
    navigator.clipboard.writeText(val).then( () => {
      this.toastr.success('Text copied to clipboard');
    }).catch( () => {
      this.toastr.error('Failed to copy to clipboard');
    });
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Rahul MM
  • 1
  • 3