Al trabajar con datos, registros, listas, muchas veces nos solicitan poder descargarlos en Excel, la librería https://sheetjs.com/ nos permite crear y manipular archivos de Excel desde el navegador o un servidor, es decir se puede usar tanto en proyectos Angular como en Node.
Su instalación es sencilla con NPM
1 |
npm i --save https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz |
También hay otras formas de instalar en la página oficial:
https://docs.sheetjs.com/docs/getting-started/installation/frameworks
Luego podemos importarlo en nuestro proyecto:
1 |
import * as XLSX from 'xlsx'; |
O si solo lo necesitas en un método en específico, cargarlo en una variable:
1 |
const XLSX = require('xlsx'); |
Esta librería nos permite convertir datos, array, objetos json a una hoja de Excel listos para convertir en archivo y descargarlo. Así como también nos permite leer archivos en Excel y poder manipularlos.
Lo que se complica es la parte de lectura desde archivos locales del proyecto, supongamos que tengas una plantilla con títulos y solo quieras “llenarla” con los datos.
Ejemplo que tengas una ruta «assets/misplantillas/reporte.xlsx»
Primero el navegador no permite acceder a rutas locales, incluso aparecerá un error «_fs.readFileSync is not a function», donde los métodos para acceder archivos no pueden realizar la acción. En node no habría problemas porque se ejecutaría desde el lado del servidor.
Segundo para estos casos la página oficial recomienda es cargarlo por petición HTTP, acceder por la ruta URL como si fuese un elemento externo y luego leer el archivo en binario para luego pasarlo al lector de archivos de Excel. Nos obliga a realizar más pasos, pero no hay otra alternativa.
Ejemplo comentando del proceso, un servicio «ExcelDownloadService»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import * as FileSaver from 'file-saver'; @Injectable({ providedIn: 'root' }) export class ExcelDownloadService { private httpClient: HttpClient; constructor( http: HttpClient ) { this.httpClient = http; } // dataJson es un array de objetos "array[]={ columna: dato }" createExcel(dataJson: any, nameFile: string) { // Importamos la libreria manualmente import("xlsx").then(xlsx => { const templateFile = "assets/misplantillas/reporte.xlsx"; // Buscamos el archivo excel desde una petición http this.httpClient.get(templateFile, { responseType: 'blob' }) .subscribe((data: any) => { const reader: FileReader = new FileReader(); // Al obtener el archivo "data", debemos leerlo con FileReader // asociamos una función al "onload" para ejecutarla cuando cargue reader.onload = (e: any) => { const bstr: string = e.target.result; const wb = xlsx.read(bstr, {type: 'binary'}); // Le indicamos a la librería que lea el archivo como binario const firstSheetName = wb.SheetNames[0]; // Obtenemos el nombre de la primera pestaña const sheet = wb.Sheets[firstSheetName]; // Obtenemos la pestaña según el nombre // A la pestaña le agregamos los datos nuevos dataJson, saltándonos el encabezado y empezando en la fila 3 xlsx.utils.sheet_add_json(sheet, dataJson, { skipHeader:true, origin: "A3" }); // Creamos el archivo nuevo y lo mandamos a descargar por el navegador const excelBuffer: any = xlsx.write(wb, { bookType: 'xlsx', type: 'array' }); this.saveFile(excelBuffer, nameFile); }; // Arriba se asocia la función al "onload", aquí ejecutamos el reader que luego ejecuta el "onload" reader.readAsBinaryString(data); }); }); } // Recibe el Excel y lo genera para descargar desde el navegador private saveFile(buffer: any, fileName: string): void { const data: Blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8" }); FileSaver.saveAs(data, fileName + ".xksx"); } } |
En las opciones coloqué «{ skipHeader:true, origin: «A3» });» porque automáticamente se toma los atributos del Json como columnas título, para ello el skipHeader y origin que comenzara en Fila A3 porqué en mi plantilla tengo dos títulos:
[ Reporte Principal ]
[Sección 1][ Sección 2 ][ Sección 3 ]
[datos][datos][datos][datos][datos]
Así que debes modificar las opciones según lo que requieras.
También he visto que se puede usar con archivos Excel cargados en un formulario, donde el archivo se obtiene directamente y no tendrías que leer el archivo local pero eso ya son otros casos y otros procesos.
Nota: Esta librería es la versión comunity y no permite el uso de estilos “negritas”, “centrar celdas”, etc. Incluso si el template tiene estilos, se borrarían. Para poder usar estilos te piden que compres la versión PRO, también podrías usar alguna de las alternativas basadas en Forks donde le incluyen una parte de estilos.