Angular 5 - Copiar para a área de transferência

124

Estou tentando implementar um ícone que, ao ser clicado, salvará uma variável na área de transferência do usuário. Atualmente, experimentei várias bibliotecas e nenhuma delas foi capaz de fazer isso.

Como copio corretamente uma variável para a área de transferência do usuário no Angular 5?

dev anônimo
fonte
você pode usar o ngxyz-c2c , existem várias maneiras de fazer isso.
Ankit Singh
Se você estiver usando Angular Material, a versão 9.0.0 (lançada em 6 de fevereiro de 2020) introduziu o pacote de área de transferência super fácil de usar . Veja a documentação do Angular e a resposta de @Nabel .
George Hawkins

Respostas:

235

Solução 1: copie qualquer texto

HTML

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

arquivo .ts

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);
  }

Solução 2: Copiar de um TextBox

HTML

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

arquivo .ts

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

Demonstração aqui


Solução 3: importar uma diretiva de terceiros ngx-clipboard

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

Solução 4: Diretiva Personalizada

Se você preferir usar uma diretiva personalizada, verifique a resposta de Dan Dohotaru, que é uma solução elegante implementada usando ClipboardEvent.

Sangram Nandkhile
fonte
1
Ótima ideia, mas eu copiei sua segunda solução e continuo obtendo o Cannot read property 'select' of undefinedangular 6. Este angular6 é compatível?
slevin
1
@slevin Não acho que esteja relacionado à versão angular de forma alguma. Você adicionou `# userinput` à sua entrada?
Sangram Nandkhile
1
@SangramNandkhile Eu verifiquei várias vezes, mas ainda o mesmo erro. Este é o meu código <input *ngIf="invitation_code" type="text" readonly value="{{invitation_code}}" #userinput > <button *ngIf="code_success" (click)="copyInputMessage(userinput)" value="click to copy" > Copy code </button>Obrigado
slevin
Você pode até mesmo remover o position, left, top, e opacity. e substitua-o por umselBox.style.height = '0';
Mendy
problema menor, deve usar const not let
Stephen DuMont
70

Eu sei que isso já foi bem votado aqui agora, mas prefiro ir para uma abordagem de diretiva personalizada e confiar no ClipboardEvent como @jockeisorby sugeriu, ao mesmo tempo que me certifico de que o ouvinte foi removido corretamente (a mesma função precisa ser fornecida para adicionar e remover ouvintes de eventos)

demonstração stackblitz

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);
  }
}

e então usá-lo como tal

<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`);
}

Nota: observe que o window["clipboardData"]é necessário para o IE, pois ele não compreendee.clipboardData

Dan Dohotaru
fonte
3
Parabéns por tornar esta diretiva reutilizável. Boa ideia!
Rod
1
na verdade, começando com a versão 12.x algo, o Safari é novamente problemático :)
Dan Dohotaru
2
uma solução mínima seria criar um intervalo e adicionar esse intervalo à seleção, uma solução de trabalho seria semelhante a stackblitz.com/edit/angular-labs-copy-clipboard-r1
Dan Dohotaru
janela ["clipboardData"] é indefinida para mim no IE? Qualquer ideia ?
Victor Jozwicki
não funciona no celular, usei o plugin ngx-clipboard em vez
the-catalin
48

Acho que esta é uma solução muito mais limpa ao copiar texto:

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

E então basta chamar copyToClipboard no evento click em html. (clique) = "copyToClipboard ('texttocopy')"

Jockeisorby
fonte
2
não funciona no IE devido ao fato de que e.clipboardData não está definido.
Dan Dohotaru
9
além disso, o removelistener também não funciona, pois o ouvinte original precisa ser passado como um argumento
Dan Dohotaru
2
Veja aqui como fazer com que o listener de remoção de eventos funcione: stackoverflow.com/a/51843984/3849445
user123959
Funciona bem no Angular 6! Testado no Chrome. Obrigado.
moreirapontocom
16

A partir do Angular Material v9, agora tem um CDK para prancheta

Área de transferência | Material Angular

Pode ser usado simplesmente

<button [cdkCopyToClipboard]="This goes to Clipboard">Copy this</button>
Nabel
fonte
Ele funciona como um encanto. Nunca soube que uma solução adequada estava lá!
Abdullah Feroz
1
disponível em Angular Material v9.
andreivictor
14

Versão modificada da resposta de jockeisorby que corrige o manipulador de eventos não sendo removido corretamente.

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
fonte
1
Não funciona no Firefox. Erro -document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler
OPTIMUS
3

Você pode conseguir isso usando módulos angulares:

navigator.clipboard.writeText('your text').then().catch(e => console.error(e));
Anantharaman Krishnamoorthy
fonte
1

O método abaixo pode ser usado para copiar a mensagem: -

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
fonte
Esta é realmente uma boa solução. Eu tentei no meu aplicativo e funcionou. Obrigado.
jaihind
1

A melhor maneira de fazer isso no Angular e manter o código simples é usar este projeto.

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
fonte
1

Copie usando CDK angular,

Module.ts

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

Copie programaticamente uma string: MyComponent.ts,

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

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

Clique em um elemento para copiar via HTML:

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

Referência: https://material.angular.io/cdk/clipboard/overview

Chandrahasan
fonte
0

A primeira solução sugerida funciona, só precisamos mudar

selBox.value = val;

Para

selBox.innerText = val;

ou seja,

HTML:

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

arquivo .ts:

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);
  }
Shreeketh K
fonte