Skip to main content

Command Palette

Search for a command to run...

Exportando datos a PDF con Angular

Updated
6 min read
S

I have worked as a frontend and backend developer handling technologies such as Django, Ionic, Laravel, MySQL, Spring (Java), Oracle, NodeJS, Angular, VueJS with the goal of developing websites and mobile applications that offer high performance and are interactive.

You can learn more about me by visiting my website: www.stalinmaza.com

#frontend #backend #fullstack #javascript #nodejs #php

En esta publicación vamos a crear un servicio que permita exportar los datos de una tabla hacia un documento PDF, los cuales van a mostrarse en columnas autoajustadas.

📦 Paquetes necesarios

Primero lo que debemos hacer es importar los paquetes necesarios, entre los principales que se necesitarían son:

  • FileSaver: para poder guardar archivos desde el navegador

  • JSPDF: librería para generar PDF´s con JavaScript

  • JSPDF Autotable: complemento de jspdf para habilitar la capacidad de generar tablas PDF ya sea analizando tablas HTML o utilizando datos JavaScript directamente

import { Injectable } from '@angular/core';
import * as FileSaver from 'file-saver';
import jsPDF from 'jspdf';
import 'jspdf-autotable';
import { reduceArrayByKeys } from 'src/app/shared/helpers/utils';
import { MessagesService } from './messages.service';

📝 Interfaz para cabeceras

Lo que necesitamos luego es crear una interfaz para mantener un tipado de los datos de entrada que tendremos al momento de exportar los datos.

interface IExportHeaders {
    header: string;
    dataKey: string;
}

🔍 Función para generar cabeceras por defecto

En caso de que no se provean las cabeceras de los datos, esta función permite obtenerlas a partir de las keys de los objetos.

const getDefaultHeaders = (json) => {
    const defaultHeaders = [];
    const keysObj = Object.keys(json);
    for (let value of keysObj) {
        const tempObj = {
            header: value, dataKey: value
        };
        defaultHeaders.push(tempObj)
    }
    return defaultHeaders;
}

⚙️ Configuración de PDF

Luego de eso se procede a escribir la configuración del objeto de JSPDF donde se puede configurar entre otras cosas la orientación del papel.

const PDFConfig = { putOnlyUsedFonts: true, orientation: 'landscape' };

Hecho eso ya podemos estructurar el servicio con su decorador tal cual como cualquier servicio normal de Angular, en el cual importamos un servicio para mostrar mensajes en el constructor del servicio.

@Injectable({ providedIn: 'root' })
export class ArchivosService {

    constructor(
        private messagesService: MessagesService
    ) { }

Luego si especificamos la función que hará el trabajo de crear el PDF y guardarlo en el dispositivo del usuario. En este caso recibimos 4 parámetros:

  • data: lo especificamos con un array de cualquier tipo ya que va a ser utilizado por múltiples componentes en nuestra aplicación

  • headers: se recibe las cabeceras que se mostrarán en las columnas de la tabla

  • filename: el nombre del archivo a exportarse

  • headerTitle: el título que aparecerá

exportPDF(
    data: any[],
    headers: IExportHeaders[] = [],
    filename = 'file',
    headerTitle = 'Documento eFact'
)

Luego verificamos si recibimos un array vacío, en ese caso retornamos un mensaje indicando que no existen datos disponibles para exportar.

if (data.length === 0) {
    return this.messagesService.info_notification(
        'No hay datos disponibles para exportar'
    );
}

También verificamos que si no se enviaron las cabeceras, las obtenemos usando la función que definimos anteriormente

if (!headers || headers.length === 0) {
    headers = getDefaultHeaders(data[0]);
}

Una vez que pasaron los datos las validaciones anteriores, se configura el documento jsPDF en el cual se configura el título del documento con tamaño de letra 18 y lo demás del documento con tamaño 8.

this.messagesService.info_notification('Generando su documento PDF...');
const doc = new jsPDF(PDFConfig);
doc.setFontSize(18);
doc.text(headerTitle, 14, 14);
doc.setFontSize(8);

const objColumns = {};
for (const header of headers) {
  objColumns[header.dataKey] = { columnWidth: 'auto' };
}

Luego de eso configuramos el método autoTable que se añade en el objeto jsPDF donde se establecen algunos parámetros como las columnas, el contenido de la tabla, la configuración de ancho de las columnas, el tema de la tabla entre otras configuraciones más.

doc.autoTable({
  columns: headers,
  body: data,
  startY: 20,
  columnStyles: objColumns,
  theme: 'striped',
  tableWidth: 'auto',
  cellWidth: 'wrap',
  showHead: 'firstPage',
  headStyles: { fillColor: [52, 152, 219] },
  styles: {
    overflow: 'linebreak',
    cellWidth: 'wrap',
    fontSize: 8,
    cellPadding: 2,
    overflowColumns: 'linebreak'
  }
});

Para obtener el numero de paginas, se usa el método getNumberOfPages que provee el método internal del documento y se procede a calcular el alto de la página.

const pageNumber = doc.internal.getNumberOfPages();
const pageSize = doc.internal.pageSize;
const pageHeight = pageSize.height || pageSize.getHeight();

Por último se ejecuta la función addFooters que se encarga de añadir el número de página en cada página del documento, el texto puede ser personalizado así como la ubicación del mismo. En el documento se establece el número de páginas y se ejecuta el método save del documento JSPDF.

function addFooters() {
  for (let i = 0; i < pageNumber; i++) {
    doc.text(`Página ${i + 1} de ${pageNumber}`, 14, pageHeight - 10);
  }
}

addFooters();
doc.setPage(pageNumber);
doc.save(`${filename}`);

Un ejemplo de como usar este servicio seria de esta manera, importándolo en el constructor de tu componente y llamando al método del servicio.

constructor(
    private _archivosService: ArchivosService 
){
}


print(){
    const headers = [
        {  header: 'Id', dataKey: 'id' },
        {  header: 'Nombre', dataKey: 'nombre'}
    ];
    const data = [
        { id: 1, nombre: 'Alexander Arnold' },
        { id: 2, nombre: 'Mariela Lopez' }
    ];
    this.exportPDF(data, headers, "usuarios.pdf", "Usuarios")
}

Listo, ya has escrito tu primer servicio que te permitirá exportar documentos PDF mandando un array de datos, el cual claramente lo puedes modificar para imprimir lo que consideres necesario.

Ejemplo:

📂 Estructura del ejemplo

  • archivos.service.ts → Tu servicio para exportar a PDF (ya lo tienes).

  • usuarios.component.ts → Componente que usa el servicio.

  • usuarios.component.html → Vista con tabla y botón.

  • usuarios.component.css → Estilos básicos.

usuarios.component.ts

import { Component } from '@angular/core';
import { ArchivosService } from '../services/archivos.service';

@Component({
  selector: 'app-usuarios',
  templateUrl: './usuarios.component.html',
  styleUrls: ['./usuarios.component.css']
})
export class UsuariosComponent {

  // Datos de ejemplo
  usuarios = [
    { id: 1, nombre: 'Alexander Arnold', email: 'alex@example.com' },
    { id: 2, nombre: 'Mariela Lopez', email: 'mariela@example.com' },
    { id: 3, nombre: 'Carlos Pérez', email: 'carlos@example.com' }
  ];

  constructor(private archivosService: ArchivosService) {}

  exportarPDF() {
    const headers = [
      { header: 'ID', dataKey: 'id' },
      { header: 'Nombre', dataKey: 'nombre' },
      { header: 'Email', dataKey: 'email' }
    ];

    this.archivosService.exportPDF(
      this.usuarios,
      headers,
      'usuarios.pdf',
      'Lista de Usuarios'
    );
  }
}

usuarios.component.html

<div class="container">
  <h2>Lista de Usuarios</h2>

  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Nombre</th>
        <th>Email</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let usuario of usuarios">
        <td>{{ usuario.id }}</td>
        <td>{{ usuario.nombre }}</td>
        <td>{{ usuario.email }}</td>
      </tr>
    </tbody>
  </table>

  <button (click)="exportarPDF()">📄 Exportar a PDF</button>
</div>

usuarios.component.css

.container {
  max-width: 600px;
  margin: auto;
  text-align: center;
  font-family: Arial, sans-serif;
}

h2 {
  margin-bottom: 20px;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 15px;
}

table, th, td {
  border: 1px solid #ccc;
}

th {
  background-color: #3498db;
  color: white;
  padding: 8px;
}

td {
  padding: 8px;
}

button {
  background-color: #2ecc71;
  color: white;
  border: none;
  padding: 10px 15px;
  cursor: pointer;
  border-radius: 4px;
}

button:hover {
  background-color: #27ae60;
}

🔹 Cómo funciona

  1. El usuario ve la tabla con los datos.

  2. Al hacer clic en "Exportar a PDF", se llama al método exportarPDF() del componente.

  3. Este método prepara las cabeceras y llama al servicio ArchivosService.

  4. El servicio genera el PDF con jsPDF y autoTable y lo descarga automáticamente.

R

El post es muy interesante pero carece de una explicación más completa para los que apenas estamos iniciando en el mundo de angular, como recomendación deberías indicarnos como quedan los archivos finales ya que estoy un poco perdido principalmente en el del servicio. Gracias.

S

Muchas gracias por el feedback, espero pronto darle una mejora en la redacción

More from this blog

S

Stalin Maza Blog

25 posts

Desarrollador apasionado por la tecnología. En este blog comparto lo que aprendo, repaso conceptos clave y documento soluciones útiles que me han servido en mi camino profesional.