Pegar cuadrícula Angular de Excel

    La Ignite UI for Angular IgxGrid puede leer datos de Excel que se copian en el portapapeles. En esta sección le mostraremos cómo hacer esto con un código personalizado.

    Angular Paste from Excel Example

    Este ejemplo demuestra cómo implementar el pegado desde Excel en la tabla de UI de materiales igxGrid. Para trabajar con la muestra, abra cualquier hoja de cálculo de Excel, copie algunas filas y péguelas en la cuadrícula usando el teclado (Ctrl + V, Mayús + Insertar, Comando + V).

    En la parte superior hay un botón desplegable con 2 opciones:

    1. "Pegar datos como filas nuevas": en este modo, cualquier dato copiado de Excel se agregará a la cuadrícula como filas nuevas.
    2. "Pegar desde la celda activa": en este modo se sobrescribirán los datos de la cuadrícula.

    Los nuevos datos después del pegado están decorados en cursiva.

    Usage

    Debe agregar la directiva paste-handler (puede encontrar su código en la siguiente sección) a igxGrid y manejar su evento onDataProcessed. El evento onDataProcessed tiene un parámetro que le brinda acceso a los datos de Excel en forma de matriz. Como referencia, consulte los métodos addRecords y updateRecords.

    <igx-grid #grid1 [data]="data" [width]="'100%'" [height]="'505px'" [autoGenerate]="false" paste-handler (onDataProcessed)="dataPasted($event)" [primaryKey]="'ID'">
        <igx-column [field]="'Name'"></igx-column>
        <igx-column [field]="'Title'"></igx-column>
        <igx-column [field]="'Phone'"></igx-column>
        <igx-column [field]="'Country'"></igx-column>
    </igx-grid>
    
        public dataPasted(processedData) {
            if (this.pasteMode === "Paste data as new records") {
                this.addRecords(processedData);
            } else {
                this.updateRecords(processedData);
            }
        }
    
        public addRecords(processedData: any[]) {
            const columns = this.grid1.visibleColumns;
            const pk = this.grid1.primaryKey;
            const addedData = [];
            for (const curentDataRow of processedData) {
                const rowData = {};
                for (const col of columns) {
                    rowData[col.field] = curentDataRow[col.visibleIndex];
                }
                // generate PK
                rowData[pk] = this.grid1.data.length + 1;
                this.grid1.addRow(rowData);
                addedData.push(rowData);
                this.grid1.cdr.detectChanges();
            }
            // scroll to last added row
            this.grid1.verticalScrollContainer.scrollTo(this.grid1.data.length);
    
            this.grid1.verticalScrollContainer.chunkLoad.pipe(take(1)).subscribe(() => {
                this.clearStyles();
                for (const data of addedData) {
                    const row = this.grid1.getRowByKey(data[pk]);
                    if (row) {
                        row.nativeElement.style["font-style"] = "italic";
                        row.nativeElement.style.color = "gray";
                    }
                }
            });
        }
        public updateRecords(processedData: any[]) {
            const cell = this.grid1.selectedCells[0];
            const pk = this.grid1.primaryKey;
            if (!cell) { return; }
            const rowIndex = cell.row.index;
            // const rowPkValue = cell.row.data[pk];
            const cellIndex = cell.column.visibleIndex;
            const columns = this.grid1.visibleColumns;
            let index = 0;
            const updatedRecsPK = [];
            for (const curentDataRow of processedData) {
                const rowData = {};
                const dataRec = this.grid1.data[rowIndex + index];
                const rowPkValue = dataRec ? dataRec[pk] : this.grid1.data.length + 1;
                rowData[pk] = rowPkValue;
                for (let j = 0; j < columns.length; j++) {
                    let currentCell;
                    if (j >= cellIndex) {
                        currentCell = curentDataRow.shift();
                    }
                    const colKey = columns[j].field;
                    rowData[colKey] = currentCell || (!!dataRec ? dataRec[colKey] : null);
                }
                if (!dataRec) {
                    // no rec to update, add instead
                    rowData[pk] = rowPkValue;
                    this.grid1.addRow(rowData);
                    continue;
                }
                this.grid1.updateRow(rowData, rowPkValue);
                this.grid1.cdr.detectChanges();
                updatedRecsPK.push(rowPkValue);
                index++;
            }
    
            this.clearStyles();
            for (const pkVal of updatedRecsPK) {
                const row = this.grid1.getRowByKey(pkVal);
                if (row) {
                row.nativeElement.style["font-style"] = "italic";
                row.nativeElement.style.color = "gray";
                }
            }
        }
    
        protected clearStyles() {
            for (const row of this.grid1.rowList.toArray()) {
                row.nativeElement.style["font-style"] = "";
                row.nativeElement.style.color = "";
            }
        }
    

    Paste Handler Directive

    Esta es la implementación del paste-handler. El código crea un elemento textarea DOM que se utiliza para recibir los datos pegados desde el portapapeles. Cuando los datos se pegan en el textarea, la directiva los analiza en una matriz y luego emite un evento personalizado onDataProcessed pasando los datos analizados.

    import { Directive, EventEmitter, HostListener, Output} from "@angular/core";
    
    @Directive({ selector: "[paste-handler]" })
    export class PasteHandler {
        public textArea;
    
        @Output()
        public onDataProcessed = new EventEmitter<any>();
    
        public ngOnInit(): void {
            const div = document.createElement("div");
            const divStyle = div.style;
            divStyle.position = "fixed";
            document.body.appendChild(div);
            this.textArea = document.createElement("textarea");
            const style = this.textArea.style;
            style.opacity = "0";
            style.height = "0px";
            style.width = "0px";
            style.overflow = "hidden";
            div.appendChild(this.textArea);
    
            this.textArea.addEventListener("paste", (eventArgs) => { this.onPaste(eventArgs); });
        }
    
        @HostListener("focusin", ["$event"])
        public focusIn(eventArgs) {
        }
    
        @HostListener("keydown", ["$event"])
        public ControlV(eventArgs) {
            const ctrl = eventArgs.ctrlKey;
            const key = eventArgs.keyCode;
            // Ctrl-V || Shift-Ins || Cmd-V
            if ((ctrl || eventArgs.metaKey) && key === 86 || eventArgs.shiftKey && key === 45) {
                this.textArea.focus();
            }
        }
    
        public onPaste(eventArgs) {
        let data;
        const clData = "clipboardData";
    
        // get clipboard data - from window.cliboardData for IE or from the original event's arguments.
        if (window[clData]) {
            window.event.returnValue = false;
            data = window[clData].getData("text");
        } else {
            data = eventArgs[clData].getData("text/plain");
        }
    
        // process the clipboard data
        const processedData = this.processData(data);
    
        this.onDataProcessed.emit(processedData);
        }
    
        public processData(data) {
            const pasteData = data.split("\n");
            for (let i = 0; i < pasteData.length; i++) {
                pasteData[i] = pasteData[i].split("\t");
                // Check if last row is a dummy row
                if (pasteData[pasteData.length - 1].length === 1 && pasteData[pasteData.length - 1][0] === "") {
                    pasteData.pop();
                }
                // remove empty data
                if (pasteData.length === 1 &&
                     pasteData[0].length === 1 &&
                      (pasteData[0][0] === "" || pasteData[0][0] === "\r")) {
                        pasteData.pop();
                }
            }
            return pasteData;
        }
    }
    
    

    API References

    Additional Resources

    • Exportador de Excel: utilice el servicio Exportador de Excel para exportar datos a Excel desde IgxGrid. También proporciona la opción de exportar solo los datos seleccionados desde IgxGrid. La funcionalidad de exportación está encapsulada en la clase IgxExcelExporterService y los datos se exportan en formato de tabla de MS Excel. Este formato permite funciones como filtrar, ordenar, etc. Para hacer esto, debe invocar el método de exportación de IgxExcelExporterService y pasar el componente IgxGrid como primer argumento.
    Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.