[JavaScript] HTML-Tabellen mit ExcelJS exportieren

<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Export Tabelle mit ExcelJS</title>
</head>
<body>
  <table id="tblTestData">
    <caption>Tabelle 1</caption>
    <thead>
      <tr>
        <th class="sub">Name</th>
        <th class="sub">Vorname</th>
        <th class="sub">Alter</th>
      </tr>
    </thead>
    <tbody>
      <tr><td>Müller</td><td>Horst</td><td>50</td></tr>
      <tr><td>Lehmann</td><td>Eduard</td><td>64</td></tr>
      <tr><td>Meier</td><td>Inge</td><td>71</td></tr>
    </tbody>
  </table>

  <div class="controls">
    <button id="btnExport" class="btn" type="button">Tabelle exportieren</button>
  </div>

  <!-- ExcelJS und FileSaver (CDN) -->
  <script src="https://cdn.jsdelivr.net/npm/exceljs/dist/exceljs.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>

  <script>
    (function () {
      const btn = document.getElementById('btnExport');

      // Näherung: 1 Excel-Char ≈ 7 Pixel
      function pxToExcelChars(px) {
        return Math.ceil(px / 7);
      }

      // charsForLen mit padding +5
      function charsForLen(len, minChars) {
        return Math.min(Math.max(len + 5, minChars), 50);
      }

      // Hilfsfunktion: ARGB aus hex (z.B. "#2f6f9f" -> "FF2F6F9F")
      function hexToARGB(hex) {
        if (!hex) return 'FFFFFFFF';
        const h = hex.replace('#','').toUpperCase();
        return (h.length === 6) ? ('FF' + h) : ('FF' + h.slice(-6));
      }

      btn.addEventListener('click', async function () {
        // HTML-Tabelle
        const table = document.getElementById('tblTestData');

        // Workbook
        const workbook = new ExcelJS.Workbook();
        // Worksheet mit Bezeichner 'Tabelle1'
        const sheet = workbook.addWorksheet('Tabelle1');

        // Farben
        const headerColor = '#2f6f9f';     // Farbe Header-Zeile
        const headerFontColor = '#FFFFFF'; // Farbe Header Schrift
        const rowOddColor = '#fbfbfb';     // Farbe gerade Zeile
        const rowEvenColor = '#FFFFFF';    // Farbe ungerade Zeile
        
        // Header-Zeile
        const headerCells = Array.from(table.tHead.rows[0].cells).map(th => th.textContent.trim());
        sheet.addRow(headerCells);
		
        // Datenzeilen aus HTML-Tabelle
		const tbody = table.tBodies[0];
		
		const iCols = table.tHead.rows[0].cells.length;
		const iRows = tbody.rows.length;

        for (let r = 0; r < iRows; r++) {
          const cells = Array.from(tbody.rows[r].cells).map(td => td.textContent.trim());
          sheet.addRow(cells);
        }

        // Beispiel: Zellen mergen
        //sheet.mergeCells('A1:C1'); // A-C

        const headerARGB = hexToARGB(headerColor);
        const headerFontARGB = hexToARGB(headerFontColor);
        const oddARGB = hexToARGB(rowOddColor);
        const evenARGB = hexToARGB(rowEvenColor);

        // Setze Arial und Standardformat für alle Zellen
        sheet.eachRow({ includeEmpty: true }, function(row, rowNumber) {
          row.eachCell({ includeEmpty: true }, function(cell, colNumber) {
            cell.font = cell.font || {};
            cell.font.name = 'Arial';
            // Default alignment left for non-specified cells
            cell.alignment = cell.alignment || { vertical: 'middle', horizontal: 'left' };
          });
        });

        // Formatierung für Header
        for (let c = 1; c <= iCols; c++) {
          const cell1 = sheet.getCell(1, c);
          cell1.font = Object.assign({}, cell1.font, { name: 'Arial', bold: true, color: { argb: headerFontARGB } });
          cell1.alignment = { vertical: 'middle', horizontal: 'center' };
          cell1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: headerARGB } };
        }

        // für gemergedte Zellen (D1, I1, N1) loopen
        // ['D1','I1','N1'].forEach(addr => {
        //  const cell = sheet.getCell(addr);
        //  cell...
        //});

        // Datenzeilen zentrieren
        const firstDataRow = 1;
        const startCol = 3; // C
        const endCol = 3;   // C
        for (let r = firstDataRow; r <= sheet.rowCount; r++) {
          const row = sheet.getRow(r);
          for (let c = startCol; c <= endCol; c++) {
            const cell = row.getCell(c);
            cell.alignment = Object.assign({}, cell.alignment || {}, { horizontal: 'center', vertical: 'middle' });
            cell.font = Object.assign({}, cell.font || {}, { name: 'Arial' });
          }
        }

        // alternierende Datenzeilen-Farben
        for (let r = 0; r < tbody.rows.length; r++) {
          const excelRowIndex = 2 + r; // ab der zweiten Zeile (ohne Header)
          const isOdd = (r % 2 === 0); // r=0 -> erste data row -> odd style (#fbfbfb)
          const fillColor = isOdd ? oddARGB : evenARGB;
          for (let c = 1; c <= iCols; c++) {
            const cell = sheet.getCell(excelRowIndex, c);
            cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
          }
        }

        // Spaltenbreiten: orientiert an der Header-Zeile (padding +5)
        const headerLens = headerCells.map(h => h ? String(h).length : 0);

        function maxLen(startIdx, endIdx) {
          let m = 0;
          for (let i = startIdx; i <= endIdx; i++) {
            if (headerLens[i] > m) m = headerLens[i];
          }
          return m;
        }

        // Spaltenbreite
        const maxColLen = maxLen(0, iCols - 1);  // A(0) .. C(2)
        // Mindestbreite 20px in Excel-Char-Einheiten
        const minChars = pxToExcelChars(20);
        // Spaltenbreite mit Padding (+5 px)
        const maxColLenPad = charsForLen(maxColLen, minChars);
		
        const cols = [];
		
        for (let i = 0; i < iCols; i++) {
          cols.push({ width: maxColLenPad });
        }
        sheet.columns = cols;

        // Rahmen
        const thinBorder = { style: 'thin' };
        const fullBorder = { top: thinBorder, left: thinBorder, bottom: thinBorder, right: thinBorder };
        // Iteriere über alle Zeilen und Spalten und setze border
        for (let r = 1; r <= sheet.rowCount; r++) {
          const row = sheet.getRow(r);
          for (let c = 1; c <= iCols; c++) {
            const cell = row.getCell(c);
            cell.border = fullBorder;
          }
        }

        // Datei: Export über Buffer für Kompatibiliät mit allen Browsern
        const buf = await workbook.xlsx.writeBuffer();

        const filename = `Test.xlsx`;

        const blob = new Blob([buf], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
		
        saveAs(blob, filename);
      });
    })();
  </script>
</body>
</html>

[JavaScript] JSON-Datei per fetch( ) oder FilePicker laden

Im Beispiel wird eine JSON-Datei eingelesen. Hierzu gibt es zwei Vorgehensweisen:

  1. Zuerst wird versucht die Datei per fetch() zu laden. Herbei kann es zum Fehler „Failed to fetch“ kommen. Die Fehlerursache ist häufig, dass der Browser den Zugriff auf lokale Dateien blockiert oder die Anfrage wegen einer Cross‑Origin‑Policy ablehnt.
  2. Falls fetch( ) fehlschlägt, kann per OpenDialog (FilePicker) lokal eine Datei ausgewählt werden.
<!doctype html>
<html lang="de">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1" />
    <title>JSON-Datei per URL oder lokal laden</title>
    <style>
      #filePicker {
        margin: 8px 0;
      }
    </style>
  </head>
  <body>
    <div id="container">
      <div id="statusText">JSON-Datei laden</div>
      <br />
      <div
        id="filePicker"
        style="display: none">
        <label>JSON-Datei auswählen:</label>
        <input
          type="file"
          id="fileOpenDialog"
          accept=".json" />
      </div>
      <br />
      <div id="fileContentText">-</div>
    </div>

    <script>
      // Datei mit Beispieldaten (URL)
      //const JSON_SRC = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
      // Datei mit Beispieldaten (lokal)
      const JSON_SRC = "MyLocalFile.json";

      // Beispielhafte Weiterverarbeitung der JSON-Daten
      function processJSON(json) {
        if (json != null) {
          document.getElementById("statusText").textContent =
            "JSON-Datei wurde geladen und wird nun weiter verarbeitet.";

          const text = JSON.stringify(json, null, 2);

          document.getElementById("fileContentText").textContent = text;
        }
      }

      document.addEventListener("DOMContentLoaded", () => {
        const txtStatusText = document.getElementById("statusText");

        // erst automatischer Ladevorgang per fetch( ) probieren,
        // bei Fehler Fallback: manueller Datei-Upload
        fetch(JSON_SRC)
          .then((resp) => {
            if (!resp.ok) throw new Error("HTTP " + resp.status);

            // JSON zu Objekt parsen
            return resp.json();
          })
          .then((json) => {
            // ggf. statusText ausblenden
            // txtStatusText.style.display = 'none';

            // JSON verarbeiten
            processJSON(json);
          })
          .catch((err) => {
            txtStatusText.textContent =
              "Fehler beim automatischen Laden: " + err.message;

            // wenn Datei nicht per fetch( ) geladen werden kann,
            // FilePicker anzeigen und dann manuelle Angabe der Datei
            document.getElementById("filePicker").style.display = "block";
          });

        const fileInput = document.getElementById("fileOpenDialog");
        // manueller Datei‑Upload

        fileInput.addEventListener("change", (ev) => {
          const f = ev.target.files && ev.target.files[0];

          if (!f) return;

          const reader = new FileReader();

          reader.onload = function (e) {
            try {
              // JSON zu Objekt parsen
              const json = JSON.parse(e.target.result);

              // ggf. statusText ausblenden
              //document.getElementById('statusText').style.display = 'none';

              // JSON verarbeiten
              processJSON(json);
            } catch (ex) {
              document.getElementById("statusText").textContent =
                "Fehler: Ungültige JSON-Datei.";
            }
          };

          reader.onerror = function () {
            document.getElementById("statusText").textContent =
              "Fehler beim Lesen der Datei.";
          };

          reader.readAsText(f);
        });
      });
    </script>
  </body>
</html>

Links

[JavaScript] Nützliche JavaScript Bibliotheken

GUI

Toastify

  • lightweight, vanilla JS toast notification library

sweetalert2

  • lightweight, vanilla JS toast notification library

Day.js

  • minimalistische Bibliothek zum handeln von Daten und Uhrzeiten

Luxon

  • Bibliothek zum handeln von Daten und Uhrzeiten

Wickedpicker

  • A simple jQuery timepicker plugin – Turn any input element into a elegant timepicker

CodeMirror

  • a versatile text editor implemented in JavaScript for the browser

JsonTree.js

  • JSON Visualisierung

jsTree

  • interaktive, anpassbare Baumansicht

TreeJS

  • simple JavaScript library, to display a TreeView like in the windows filebrowser

Fancytree

  • JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag’n’drop, and lazy loading
  • https://wwwendt.de/tech/fancytree/

wunderbaum

Utils

async

  • Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript

FingerprintJS

  • client-side, browser fingerprinting library

ZXing („zebra crossing“)

  • Barcodes und QR-Codes prozessieren

Cryptographie

CryptoJS

  • JavaScript implementations of standard and secure cryptographic algorithms

Kartendaten

Leaflet

  • Open-source JavaScript library for mobile-friendly interactive maps

deck.gl

  • GPU-powered framework for visual exploratory data analysis of large datasets

MapLibre

  • open-source library for publishing maps

OpenFreeMap

  • display custom maps

OpenAddresses

  • global collection of address

Office

PDF.js

  • Open Source JavaScript PDF Viewer-Bibliothek

Papa Parse

  • The powerful, in-browser CSV parser for big boys and girls

SheetJS CE

  • Import und Export von Tabellendaten mit verschiedenen Formaten (HTML-Table, JSON, CSV, xlsx, ods …)

ExcelJS

Charts

Chart.js

  • Simple, flexible JavaScript charting library

Recharts

  • React-based charting library

Plotly.js

  • 2D / 3D Chart Library

3D / WebGL

Babylon.js

  • Open Source Web 3D Engine

Three.js

  • JavaScript 3D library

Audio

Tone.js

  • Web-Audio-Framework

[JavaScript] RegEx verwenden

Variante 1

let str = '123456';
let regex = /^(\d{6})?$/;

// RegEx testen
// Besp: String muss aus 6 Zahlen bestehen
if (regex.test(str))
{
    console.log('match');
}
else
{
    console.log('no match');
}

Variante 2

let str = '123456';

// RegEx testen
// Besp: String muss aus 6 Zahlen bestehen
if (/^(\d{6})?$/.test(str))
{
    console.log('match');
}
else
{
    console.log('no match');
}

[AJAX] $.post()

Allgemein

$.post(URL, data, callback); 

Beispiel

// https://www.w3schools.com/jquery/jquery_ajax_get_post.asp
$("btn1").click(function(){
    // url
    $.post("btn1_post.php",
    // data
    {
        data1: "some data1",
        data2: "some data2"
    },
    // callback
    function(data, status){
        console.log("Data: " + data);
        console.log("Status: " + status);
    });
}); 

[AJAX] $.get()

Allgemein

$.get(URL, callback); 

Beispiel

// https://www.w3schools.com/jquery/jquery_ajax_get_post.asp
$("btn1").click(function(){
    // url
    $.get("btn1_get.php",
    // callback
    function(data, status){
        console.log("Data: " + data);
        console.log("Status: " + status);
    });
});