Angular 5 - Copiar al portapapeles

124

Estoy tratando de implementar un ícono que, al hacer clic, guardará una variable en el portapapeles del usuario. Actualmente he probado varias bibliotecas y ninguna de ellas ha podido hacerlo.

¿Cómo copio correctamente una variable al portapapeles del usuario en Angular 5?

anonymous-dev
fuente
puede usar ngxyz-c2c , hay varias formas de hacerlo.
Ankit Singh
Si está utilizando Angular Material, la versión 9.0.0 (lanzada el 6 de febrero de 2020) introdujo el paquete de portapapeles súper fácil de usar . Vea la documentación de Angular y la respuesta de @ Nabel .
George Hawkins

Respuestas:

236

Solución 1: copie cualquier texto

HTML

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

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

Solución 2: copiar desde un TextBox

HTML

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

archivo .ts

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

Demo aquí


Solución 3: Importe una directiva de terceros ngx-clipboard

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

Solución 4: Directiva personalizada

Si prefiere usar una directiva personalizada, consulte la respuesta de Dan Dohotaru, que es una elegante solución implementada con ClipboardEvent.

Sangram Nandkhile
fuente
1
Gran idea, pero copié su segunda solución y sigo entrando Cannot read property 'select' of undefineden angular 6. ¿Es este angular6 compatible?
slevin
1
@slevin No creo que esté relacionado con la versión angular de ninguna manera. ¿Agregó `# userinput` a su entrada?
Sangram Nandkhile
1
@SangramNandkhile Lo comprobé una y otra vez, pero seguía siendo el mismo error. Este es mi 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>Gracias
slevin
Incluso se puede eliminar el position, left, top, y opacity. y reemplazarlo con unselBox.style.height = '0';
Mendy
problema menor, debe usar const no dejar
Stephen DuMont
70

Sé que esto ya ha sido muy votado aquí por ahora, pero prefiero optar por un enfoque de directiva personalizado y confiar en ClipboardEvent como sugirió @jockeisorby, mientras que también me aseguro de que el oyente se elimine correctamente (se debe proporcionar la misma función tanto para agregar como para eliminar oyentes de eventos)

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

y luego úsalo 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: window["clipboardData"]tenga en cuenta que es necesario para IE, ya que no comprendee.clipboardData

Dan Dohotaru
fuente
3
Felicitaciones por hacer de esta una directiva reutilizable. ¡Gran idea!
Rod
1
de hecho, comenzando con la versión 12.x algo, Safari es nuevamente problemático :)
Dan Dohotaru
2
una solución alternativa mínima sería crear un rango y agregar ese rango a la selección, una solución de trabajo se vería así: stackblitz.com/edit/angular-labs-copy-clipboard-r1
Dan Dohotaru
¿La ventana ["clipboardData"] no está definida para mí en IE? Alguna idea ?
Victor Jozwicki
no funciona en dispositivos móviles, utilicé el complemento ngx-clipboard en su lugar
the-catalin
50

Creo que esta es una solución mucho más limpia al copiar texto:

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

Y luego simplemente llame a copyToClipboard al hacer clic en el evento en html. (clic) = "copyToClipboard ('texttocopy')"

jockeisorby
fuente
2
no funciona en IE debido al hecho de que e.clipboardData no está definido.
Dan Dohotaru
9
además, el escuchador de remoción tampoco funciona, ya que el oyente original debe pasarse como argumento
Dan Dohotaru
2
Busque aquí cómo hacer que funcione el detector de eventos de eliminación: stackoverflow.com/a/51843984/3849445
user123959
¡Funciona bien en Angular 6! Probado en Chrome. Gracias.
moreirapontocom
16

A partir de Angular Material v9, ahora tiene un CDK de portapapeles

Portapapeles | Material angular

Puede usarse tan simplemente como

<button [cdkCopyToClipboard]="This goes to Clipboard">Copy this</button>
Nabel
fuente
Funciona a las mil maravillas. ¡Nunca supe que había una solución adecuada!
Abdullah Feroz
1
disponible en Angular Material v9.
andreivictor
14

Versión modificada de la respuesta de jockeisorby que corrige que el controlador de eventos no se elimina correctamente.

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);
}
Juan
fuente
1
No funciona en Firefox. Error -document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler
OPTIMUS
3

Puede lograr esto usando módulos angulares:

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

El siguiente método se puede utilizar para copiar el mensaje: -

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
fuente
De hecho, esta es una buena solución. Lo probé para mi aplicación y funcionó. Gracias.
jaihind
1

La mejor manera de hacer esto en Angular y mantener el código simple es usar este proyecto.

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

Copiar usando angular cdk,

Module.ts

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

Copie mediante programación una cadena: MyComponent.ts,

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

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

Haga clic en un elemento para copiar a través de HTML:

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

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

Chandrahasan
fuente
0

La primera solución sugerida funciona, solo necesitamos cambiar

selBox.value = val;

A

selBox.innerText = val;

es decir,

HTML:

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

Archivo .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
fuente