Angular 5 - Copier dans le presse-papier

124

J'essaie d'implémenter une icône qui, lorsqu'elle est cliquée, enregistre une variable dans le presse-papiers de l'utilisateur. J'ai actuellement essayé plusieurs bibliothèques et aucune d'entre elles n'a pu le faire.

Comment copier correctement une variable dans le presse-papiers de l'utilisateur dans Angular 5?

anonyme-dev
la source
vous pouvez utiliser ngxyz-c2c , il existe plusieurs façons de le faire.
Ankit Singh
Si vous utilisez Angular Material, la version 9.0.0 (publiée le 6 février 2020) a introduit le package de presse-papiers super facile à utiliser . Voir la documentation Angular et la réponse de @ Nabel .
George Hawkins

Réponses:

236

Solution 1: copiez n'importe quel texte

HTML

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

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

Solution 2: Copier à partir d'une zone de texte

HTML

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

fichier .ts

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

Démo ici


Solution 3: importer une directive tierce ngx-clipboard

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

Solution 4: Directive personnalisée

Si vous préférez utiliser une directive personnalisée, consultez la réponse de Dan Dohotaru qui est une solution élégante implémentée à l'aide de ClipboardEvent.

Sangram Nandkhile
la source
1
Excellente idée, mais j'ai copié votre 2ème solution et je continue à entrer Cannot read property 'select' of undefineddans angular 6. Est-ce angular6-compatible?
slevin
1
@slevin Je ne pense pas que cela soit lié à la version angulaire en aucune façon. Avez-vous ajouté «# userinput» à votre entrée?
Sangram Nandkhile
1
@SangramNandkhile J'ai vérifié encore et encore, mais toujours la même erreur. Ceci est mon code <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>Merci
slevin
Vous pouvez même retirer le position, left, topet opacity. et remplacez-le par unselBox.style.height = '0';
Mendy
problème mineur, devrait utiliser const not let
Stephen DuMont
70

Je sais que cela a déjà été fortement voté ici maintenant, mais je préfère opter pour une approche directive personnalisée et me fier au ClipboardEvent comme @jockeisorby l'a suggéré, tout en m'assurant que l'auditeur est correctement supprimé (la même fonction doit être fournie pour les écouteurs d'événements d'ajout et de suppression)

démo 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);
  }
}

puis utilisez-le comme tel

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

Remarque: notez que le window["clipboardData"]est nécessaire pour IE car il ne comprend pase.clipboardData

Dan Dohotaru
la source
3
Félicitations pour en avoir fait une directive réutilisable. Bonne idée!
Rod
1
en effet, à partir de la version 12.x quelque chose, Safari est à nouveau problématique :)
Dan Dohotaru
2
une solution de contournement minimale serait de créer une plage et d'ajouter cette plage à la sélection, une solution de travail ressemblerait à ceci: stackblitz.com/edit/angular-labs-copy-clipboard-r1
Dan Dohotaru
window ["clipboardData"] n'est pas défini pour moi dans IE? Une idée ?
Victor Jozwicki le
cela ne fonctionne pas sur mobile, j'ai utilisé le plugin ngx-clipboard à la place
the-catalin
50

Je pense que c'est une solution beaucoup plus propre lors de la copie de texte:

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

Et puis appelez simplement copyToClipboard sur l'événement de clic en html. (click) = "copyToClipboard ('texttocopy')"

jockeisorby
la source
2
ne fonctionne pas sur IE car e.clipboardData n'est pas défini.
Dan Dohotaru
9
de plus, le removelistener ne fonctionne pas non plus car l'auditeur d'origine doit être passé comme argument
Dan Dohotaru
2
Regardez ici pour savoir comment faire fonctionner l'écouteur d'événement de suppression: stackoverflow.com/a/51843984/3849445
user123959
Fonctionne bien dans Angular 6! Testé dans Chrome. Je vous remercie.
moreirapontocom
16

À partir de Angular Material v9, il dispose désormais d'un presse-papiers CDK

Presse-papiers | Matériau angulaire

Il peut être utilisé aussi simplement que

<button [cdkCopyToClipboard]="This goes to Clipboard">Copy this</button>
Nabel
la source
Il fonctionne comme un charme. Je n'ai jamais su qu'une solution appropriée était là!
Abdullah Feroz
1
disponible auprès de Angular Material v9.
andreivictor le
14

Version modifiée de la réponse de jockeisorby qui corrige le gestionnaire d'événements n'étant pas correctement supprimé.

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
la source
1
Ne fonctionne pas dans Firefox. Erreur -document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler
OPTIMUS
3

Vous pouvez y parvenir en utilisant des modules angulaires:

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

La méthode ci-dessous peut être utilisée pour copier le 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
la source
C'est en effet une bonne solution. Je l'ai essayé pour mon application et cela a fonctionné. Merci.
jaihind le
1

La meilleure façon de faire cela dans Angular et de garder le code simple est d'utiliser ce projet.

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
la source
1

Copier en utilisant un cdk angulaire,

Module.ts

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

Copiez par programme une chaîne: MyComponent.ts,

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

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

Cliquez sur un élément à copier via HTML:

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

Référence: https://material.angular.io/cdk/clipboard/overview

Chandrahasan
la source
0

La première solution suggérée fonctionne, il suffit de changer

selBox.value = val;

À

selBox.innerText = val;

c'est à dire,

HTML:

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

Fichier .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
la source