example - ¿Cómo copio al portapapeles en Angular 2 Typescript?
copy clipboard typescript (9)
Actualmente, solo se implementan las abstracciones de API más comunes, principalmente para poder pasar diferentes implementaciones cuando se ejecutan en el servidor (representación del lado del servidor ( https://github.com/angular/universal ) dentro de un trabajador web donde la API no está disponible.
Estoy bastante seguro de que todavía no hay nada para la API del portapapeles. Sin embargo, hay planes para implementar más envoltorios.
¿Hay alguna forma de copiar texto en el portapapeles (navegador múltiple) en el marco de Angular2 Typescript?
Sólo encuentro fuentes de uso de Javascript, por ejemplo,
document.execCommand(''copy'')
Aquí hay un código simple en caso de que su texto no esté dentro de una entrada o área de texto, sino un div, o cualquier otro HTMLElement:
window.getSelection().selectAllChildren(document.getElementById(''yourID'');
document.execCommand("Copy");
No pude usar el comando select()
porque Angular no lo reconoció. ¡Espero que esto ayude a alguien!
Aquí hay una manera de lograr esto sin ninguna dependencia externa o creando elementos falsos, solo mediante el uso de la API del Portapapeles :
import { DOCUMENT } from ''@angular/common'';
import { Directive, EventEmitter, HostListener, Inject, Input, Output } from ''@angular/core'';
@Directive({
selector: ''[myClipboard]''
})
export class ClipboardDirective {
@Input() myClipboard: string;
@Output() myClipboardSuccess = new EventEmitter<ClipboardEvent>();
constructor(@Inject(DOCUMENT) private document: Document) {}
@HostListener(''click'')
onClick() {
this.document.addEventListener(''copy'', this.handler);
this.document.execCommand(''copy'');
}
private handler = (e: ClipboardEvent) => {
e.clipboardData.setData(''text/plain'', this.myClipboard);
e.preventDefault();
this.myClipboardSuccess.emit(e);
this.document.removeEventListener(''copy'', this.handler);
}
}
Ben Nadel tuvo un gran ejemplo que funcionó para cualquier tipo de elemento html y no depende de nada para instalarse. Ver la publicación del blog de Ben O ver la gist Git
Vea su blog para más información y el registro que hace, aquí está lo relevante y ligeramente modificado para que encaje mejor aquí:
Hacer una directiva: clipboard.directive.ts
// Import the core angular services.
import { Directive } from "@angular/core";
import { EventEmitter } from "@angular/core";
// Import the application components and services.
import { ClipboardService } from "./clipboard.service";
// This directive acts as a simple glue layer between the given [clipboard] property
// and the underlying ClipboardService. Upon the (click) event, the [clipboard] value
// will be copied to the ClipboardService and a (clipboardCopy) event will be emitted.
@Directive({
selector: "[clipboard]",
inputs: [ "value: clipboard" ],
outputs: [
"copyEvent: clipboardCopy",
"errorEvent: clipboardError"
],
host: {
"(click)": "copyToClipboard()"
}
})
export class ClipboardDirective {
public copyEvent: EventEmitter<string>;
public errorEvent: EventEmitter<Error>;
public value: string;
private clipboardService: ClipboardService;
// I initialize the clipboard directive.
constructor( clipboardService: ClipboardService ) {
this.clipboardService = clipboardService;
this.copyEvent = new EventEmitter();
this.errorEvent = new EventEmitter();
this.value = "";
}
// ---
// PUBLIC METODS.
// ---
// I copy the value-input to the Clipboard. Emits success or error event.
public copyToClipboard() : void {
this.clipboardService
.copy( this.value )
.then(
( value: string ) : void => {
this.copyEvent.emit( value );
}
)
.catch(
( error: Error ) : void => {
this.errorEvent.emit( error );
}
)
;
}
}
Y un servicio de clipboard.service.ts.
// Import the core angular services.
import { DOCUMENT } from "@angular/platform-browser";
import { Inject } from "@angular/core";
import { Injectable } from "@angular/core";
@Injectable()
export class ClipboardService {
private dom: Document;
// I initialize the Clipboard service.
// --
// CAUTION: This service is tightly couped to the browser DOM (Document Object Model).
// But, by injecting the "document" reference rather than trying to reference it
// globally, we can at least pretend that we are trying to lower the tight coupling.
constructor( @Inject( DOCUMENT ) dom: Document ) {
this.dom = dom;
}
// ---
// PUBLIC METHODS.
// ---
// I copy the given value to the user''s system clipboard. Returns a promise that
// resolves to the given value on success or rejects with the raised Error.
public copy( value: string ) : Promise<string> {
var promise = new Promise(
( resolve, reject ) : void => {
var textarea = null;
try {
// In order to execute the "Copy" command, we actually have to have
// a "selection" in the currently rendered document. As such, we''re
// going to inject a Textarea element and .select() it in order to
// force a selection.
// --
// NOTE: This Textarea is being rendered off-screen.
textarea = this.dom.createElement( "textarea" );
textarea.style.height = "0px";
textarea.style.left = "-100px";
textarea.style.opacity = "0";
textarea.style.position = "fixed";
textarea.style.top = "-100px";
textarea.style.width = "0px";
this.dom.body.appendChild( textarea );
// Set and select the value (creating an active Selection range).
textarea.value = value;
textarea.select();
// Ask the browser to copy the current selection to the clipboard.
this.dom.execCommand( "copy" );
resolve( value );
} finally {
// Cleanup - remove the Textarea from the DOM if it was injected.
if ( textarea && textarea.parentNode ) {
textarea.parentNode.removeChild( textarea );
}
}
}
);
return( promise );
}
}
Importe ambos en app.module.ts y luego puede hacer referencia en HTML con algo como esto:
<p>
<button [clipboard]="value1.innerHTML.trim()">
Copy Text
</button>
<span #value1>
Hello World!
</span>
</p>
El código que mencionó es la forma correcta de hacerlo y también se puede hacer en Angular 2+.
No sé qué es lo que debe hacer, pero si, por ejemplo, tiene una entrada y un botón:
(.html file)
<input id=''inputId''></input>
<button (click)="copyToClipboard()''>click me</button>
entonces todo lo que necesitas hacer es:
(.ts file)
public copyToClipboard(): void {
const inputElement = document.getElementById(''inputId'');
(<any>inputElement).select();
document.execCommand(''copy'');
inputElement.blur();
}
Esta es una solución simple y simple de Angular2 y javascript que no requiere ninguna biblioteca y que se puede utilizar en un componente angular. Puede convertirlo en un servicio o hacerlo más genérico si es necesario, pero esto establecerá la idea básica.
Actualmente, los navegadores solo permiten copiar texto en el portapapeles desde la Selección en un <input>
o <textarea>
En el componente haz algo como esto:
import {Inject} from "@angular/core";
import {DOCUMENT} from "@angular/platform-browser";
export class SomeComponent {
private dom: Document;
constructor(@Inject(DOCUMENT) dom: Document) {
this.dom = dom;
}
copyElementText(id) {
var element = null; // Should be <textarea> or <input>
try {
element = this.dom.getElementById(id);
element.select();
this.dom.execCommand("copy");
}
finally {
this.dom.getSelection().removeAllRanges;
}
}
}
Luego, en el bloque html asociado con el componente, haga lo siguiente:
<div>
<button (click)="copyElementText(''elem1'')">Copy</button>
</div>
<textarea id="elem1">Some text</textarea>
¡Eso es! El botón llama a la función copyElementText () en su componente y le pasa el ID del elemento html para obtener texto y copiarlo en el portapapeles.
La función utiliza javascript estándar para obtener el elemento por su ID, seleccionarlo, ejecutar el comando "Copiar" en la selección y luego deseleccionarlo.
Felicitaciones a @ThierryTemplier,
Basándome en su respuesta, armé una directiva y la compartí en github & npm.
Aquí está el proyecto en github
ACTUALIZACIÓN: 30/04/2017
Esta biblioteca ya no depende de clipboard.js.
¡Sólo angular!
Podría implementar una directiva Angular2 en la biblioteca de clipboard.js .
Primero configure la biblioteca en SystemJS:
<script>
System.config({
map: {
clipboard: ''https://cdn.rawgit.com/zenorocha/clipboard.js/master/dist/clipboard.js''
},
packages: {
''app'': {
defaultExtension: ''js''
}
}
});
(...)
</script>
Queremos poder adjuntar el portapapeles a un elemento a través de una directiva y proporcionar como parámetro el elemento DOM que queremos vincular. El valor especificado en el elemento de destino especificado se utilizará para copiar su texto. Aquí hay una muestra de uso:
<div>
<input #foo/>
<button [clipboard]="foo">Copy</button>
</div>
La implementación de la directiva es la siguiente:
import {Directive,ElementRef,Input,Output,EventEmitter} from ''angular2/core'';
import Clipboard from ''clipboard'';
@Directive({
selector: ''[clipboard]''
})
export class ClipboardDirective {
clipboard: Clipboard;
@Input(''clipboard'')
elt:ElementRef;
@Output()
clipboardSuccess:EventEmitter<any> = new EventEmitter();
@Output()
clipboardError:EventEmitter<any> = new EventEmitter();
constructor(private eltRef:ElementRef) {
}
ngOnInit() {
this.clipboard = new Clipboard(this.eltRef.nativeElement, {
target: () => {
return this.elt;
}
});
this.clipboard.on(''success'', (e) => {
this.clipboardSuccess.emit();
});
this.clipboard.on(''error'', (e) => {
this.clipboardError.emit();
});
}
ngOnDestroy() {
if (this.clipboard) {
this.clipboard.destroy();
}
}
}
Ver este plunkr para una muestra: https://plnkr.co/edit/elyMcP5PX3UP4RkRQUG8?p=preview .
solo tengo un método de https://github.com/pehu71/copy-component/blob/master/src/simple/copy.component.ts funciona incluso en Android 4.1.2
copy(val) {
let 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);
}