Angular 5 - Kopiuj do schowka

125

Próbuję zaimplementować ikonę, która po kliknięciu zapisze zmienną w schowku użytkownika. Obecnie wypróbowałem kilka bibliotek i żadna z nich nie była w stanie tego zrobić.

Jak poprawnie skopiować zmienną do schowka użytkownika w Angular 5?

anonymous-dev
źródło
możesz użyć ngxyz-c2c , można to zrobić na wiele sposobów.
Ankit Singh,
Jeśli używasz Angular Material, to w wersji 9.0.0 (wydanej 6 lutego 2020 r.) Wprowadzono super łatwy w użyciu pakiet schowka . Zobacz kątowego dokumentację i @ Nabel za odpowiedź .
George Hawkins

Odpowiedzi:

236

Rozwiązanie 1: Skopiuj dowolny tekst

HTML

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

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

Rozwiązanie 2: Skopiuj z TextBox

HTML

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

plik .ts

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

Demo tutaj


Rozwiązanie 3: Zaimportuj dyrektywę ngx-clipboard innej firmy

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

Rozwiązanie 4: Dyrektywa niestandardowa

Jeśli wolisz, stosując dyrektywę niestandardową, Sprawdź Dan Dohotaru za odpowiedź , która jest eleganckie rozwiązanie zaimplementowane przy użyciu ClipboardEvent.

Sangram Nandkhile
źródło
1
Świetny pomysł, ale skopiowałem twoje drugie rozwiązanie i nadal otrzymuję Cannot read property 'select' of undefinedangular 6. Czy to jest zgodne z angular6?
slevin
1
@slevin Nie sądzę, że jest to w żaden sposób związane z wersją kątową. Czy dodałeś „# userinput” do swoich danych wejściowych?
Sangram Nandkhile,
1
@SangramNandkhile Sprawdziłem raz po raz, ale nadal ten sam błąd. To jest mój kod <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>Dzięki
slevin
Można nawet usunąć position, left, top, i opacity. i zamień naselBox.style.height = '0';
Mendy
drobny problem, należy używać const nie pozwól
Stephen DuMont
70

Wiem, że zostało to już tutaj wysoko ocenione, ale wolałbym wybrać podejście z niestandardową dyrektywą i polegać na zdarzeniu ClipboardEvent, jak sugerował @jockeisorby, jednocześnie upewniając się, że odbiornik jest poprawnie usunięty (ta sama funkcja musi być zapewniona zarówno dla detektorów dodawania, jak i usuwania zdarzeń)

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

a następnie użyj go jako takiego

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

Uwaga: zwróć uwagę, że window["clipboardData"]IE jest potrzebne, ponieważ nie rozumiee.clipboardData

Dan Dohotaru
źródło
3
Brawa za uczynienie z tej dyrektywy wielokrotnego użytku. Świetny pomysł!
Rod
1
rzeczywiście, zaczynając od wersji 12.x coś, Safari znów jest problematyczne :)
Dan Dohotaru
2
minimalnym obejściem byłoby utworzenie zakresu i dodanie go do zaznaczenia, działające rozwiązanie wyglądałoby tak: stackblitz.com/edit/angular-labs-copy-clipboard-r1
Dan Dohotaru
window ["clipboardData"] jest dla mnie niezdefiniowane w IE? Dowolny pomysł ?
Victor Jozwicki
nie działa na urządzeniach mobilnych, zamiast tego użyłem wtyczki ngx-clipboard
the-catalin
50

Myślę, że jest to znacznie czystsze rozwiązanie podczas kopiowania tekstu:

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

A następnie po prostu wywołaj zdarzenie copyToClipboard po kliknięciu w html. (click) = "copyToClipboard ('texttocopy')"

jockeisorby
źródło
2
nie działa w IE, ponieważ e.clipboardData nie jest zdefiniowana.
Dan Dohotaru,
9
ponadto removelistener też nie działa, ponieważ oryginalny słuchacz musi zostać przekazany jako argument
Dan Dohotaru
2
Spójrz tutaj, jak sprawić, by działał detektor usuwania zdarzeń: stackoverflow.com/a/51843984/3849445
user123959
Działa dobrze w Angular 6! Przetestowano w Chrome. Dziękuję Ci.
moreirapontocom
16

Od wersji Angular Material v9 ma teraz CDK ze schowkiem

Schowek | Materiał kątowy

Może być używany tak prosto, jak

<button [cdkCopyToClipboard]="This goes to Clipboard">Copy this</button>
Nabel
źródło
To działa jak urok. Nigdy nie wiedziałem, że istnieje właściwe rozwiązanie!
Abdullah Feroz
1
dostępne z Angular Material v9.
andreivictor
14

Zmodyfikowana wersja odpowiedzi jockeisorby, która naprawia procedurę obsługi zdarzeń, która nie została poprawnie usunięta.

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);
}
Jan
źródło
1
Nie działa w przeglądarce Firefox. Błąd -document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler
OPTIMUS
3

Możesz to osiągnąć za pomocą modułów Angular:

navigator.clipboard.writeText('your text').then().catch(e => console.error(e));
Anantharaman Krishnamoorthy
źródło
1

Do skopiowania wiadomości można użyć poniższej metody: -

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
źródło
To rzeczywiście dobre rozwiązanie. Wypróbowałem to dla mojej aplikacji i zadziałało. Dzięki.
jaihind
1

Najlepszym sposobem na zrobienie tego w Angular i zachowanie prostoty kodu jest użycie tego projektu.

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
źródło
1

Skopiuj za pomocą kątowego cdk,

Module.ts

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

Programowo skopiuj ciąg: MyComponent.ts,

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

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

Kliknij element do skopiowania za pomocą HTML:

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

Źródła: https://material.angular.io/cdk/clipboard/overview

Chandrahasan
źródło
0

Pierwsze sugerowane rozwiązanie działa, musimy tylko zmienić

selBox.value = val;

Do

selBox.innerText = val;

to znaczy,

HTML:

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

plik .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.
źródło