UNPKG

modern-table-js

Version:

Modern, lightweight, vanilla JavaScript table library with zero dependencies. 67% faster than DataTables with mobile-first responsive design.

393 lines (360 loc) 12.3 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Test: With Authentication Token</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="/modern-table.css" rel="stylesheet" /> <link href="/responsive.css" rel="stylesheet" /> <link href="/themes.css" rel="stylesheet" /> </head> <body> <div class="container mt-4"> <h2>🚀 Test: With Authentication Token</h2> <p class="text-muted"> Testing advanced parameter transformation with sorting, search, and data preprocessing </p> <div class="card"> <div class="card-header"> <h5>Users Table (With Authentication Token)</h5> </div> <div class="card-body"> <table id="advanced-table" class="table table-striped"></table> </div> </div> </div> <!-- Modern Table Demo with DummyJSON API --> <script type="module"> import { ModernTable } from "../core/ModernTable.js"; // Setup event listeners BEFORE table initialization const table = new ModernTable("#table-users", { api: { url: "/api/users", headers: { Authorization: "Bearer " + localStorage.getItem("token"), "X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]') .content, }, // Before request is sent (like beforeSend) beforeSend: function (params) { document.getElementById("loading").style.display = "block"; // Return false to abort request }, // On successful response (like success) success: function (data, textStatus, response) { console.log("Request successful:", data); }, // On error (like error) error: function (error, textStatus, errorThrown) { console.error("Request failed:", error); alert("Failed to load data"); // Return fallback data to prevent table error return { data: [], recordsTotal: 0, recordsFiltered: 0, }; }, // Always runs (like complete) complete: function () { document.getElementById("loading").style.display = "none"; console.log("Request completed"); }, // Legacy support beforeRequest: function (config) { // Modify request config return config; }, }, columns: [ { data: "DT_RowIndex", title: "No", orderable: false, searchable: false, }, { data: "avatar_url", title: "Avatar", render: (data) => `<img src="${data}" alt="Avatar" class="rounded-circle" width="40" height="40">`, }, { data: "name", title: "Name", }, { data: "email", title: "Email", }, { data: "actions", title: "Action", className: "text-center", orderable: false, searchable: false, render: (_, __, row) => ` <button class="btn btn-sm btn-primary me-1" onclick="editUser(${row.id})"> <i class="fas fa-edit"></i> </button> <button class="btn btn-sm btn-danger" onclick="deleteUser(${row.id})"> <i class="fas fa-trash"></i> </button> `, }, ], buttons: [ { text: "Create", className: "btn btn-primary btn-sm btn-create", enabled: false, attr: { id: "btn-create", }, action: function (e, dt, node, config) { alert("Create New Data"); }, }, { text: 'Delete Bulk (<span class="selected-count">0</span>)', className: "btn btn-danger btn-sm btn-delete", enabled: false, attr: { id: "btn-bulk-delete", style: "display: block;", }, action: function (e, dt, node, config) { const selectedRows = dt.getSelectedRows(); if (selectedRows.length > 0) { alert(`Bulk delete ${selectedRows.length} selected users`); } else { alert("No users selected for deletion"); } }, }, "copy", "csv", "excel", { extend: "pdf", text: "PDF", className: "btn btn-danger btn-sm btn-pdf", filename: "Users", orientation: "landscape", pageSize: "A4", exportColumns: ["avatar_url", "name", "email"], titleAttr: "Export data as PDF file", }, { extend: "print", text: "Print", className: "btn btn-warning btn-sm btn-print", orientation: "portrait", exportColumns: ["avatar_url", "name", "email"], titleAttr: "Print selected columns with custom styling", }, "colvis", ], serverSide: true, // Features pageLength: 10, lengthMenu: [5, 10, 25, 50], order: [[2, "desc"]], // name column ordering: true, searching: true, columnSearch: true, paging: true, select: true, responsive: true, // UX theme: "auto", keyboard: true, accessibility: true, // State stateSave: true, stateDuration: 3600, filters: [ { column: "date", type: "date", label: "Registration Date", placeholder: "Select date", }, { column: "start_date", type: "date", label: "From Date", placeholder: "Start date", }, { column: "end_date", type: "date", label: "To Date", placeholder: "End date", }, { column: "year", type: "select", label: "Year", options: [ { value: "", text: "All Years", }, { value: "2024", text: "2024", }, { value: "2023", text: "2023", }, { value: "2022", text: "2022", }, ], }, { type: "clear", label: "Clear", className: "btn btn-outline-secondary btn-sm", }, ], // Called after table initialization initComplete: function (data, meta) { console.log("Table initialized with:", data.length, "rows"); }, // Called BEFORE every table draw/redraw preDrawCallback: function (settings) { console.log("About to render:", settings.data.length, "rows"); // Show loading, validate data, preprocessing // Return false to cancel rendering return true; }, // Called after every table draw/redraw drawCallback: function (settings) { console.log("Table drawn with:", settings.data.length, "rows"); // Re-bind events, apply styling, initialize tooltips, etc. document .querySelectorAll('[data-bs-toggle="tooltip"]') .forEach((el) => { new bootstrap.Tooltip(el); }); }, // Called when row DOM element is created createdRow: function (row, data, dataIndex) { // Add data attributes, CSS classes, event listeners row.setAttribute("data-user-id", data.id); if (data.role === "admin") { row.classList.add("admin-row"); } }, // Called for each row during rendering rowCallback: function (row, data, index) { // Apply conditional styling, modify row content if (data.status === "inactive") { row.classList.add("table-warning"); } }, // Called to manipulate header after each draw headerCallback: function (thead, data, start, end, display) { // Update header with dynamic info const nameHeader = thead.querySelector('th[data-column="1"]'); if (nameHeader) { const activeCount = data.filter( (user) => user.status === "active" ).length; nameHeader.title = `${activeCount} active users in current page`; } }, // Called to manipulate footer after each draw footerCallback: function (row, data, start, end, display) { if (row) { const total = data.length; const active = data.filter( (item) => item.status === "active" ).length; row.innerHTML = ` <tr> <th colspan="3">Summary:</th> <th>Active: ${active}</th> <th>Total: ${total}</th> <th colspan="2"></th> </tr> `; } }, // Called to generate custom info text infoCallback: function (settings, start, end, max, total, pre) { const percentage = total > 0 ? Math.round((total / max) * 100) : 0; return ` <div class="d-flex justify-content-between"> <span>Menampilkan ${start} sampai ${end} dari ${total} data</span> <span class="badge bg-info">${percentage}% data ditampilkan</span> </div> `; }, // Custom state loading (override built-in) stateLoadCallback: function (settings) { const state = JSON.parse(localStorage.getItem("customTableState")); if (state) { // Example: Always reset page to 1 (exclude paging from state) state.page = 1; return state; } return null; }, // Custom state saving (override built-in) stateSaveCallback: function (settings, data) { // Add custom metadata const enhancedState = { ...data, timestamp: new Date().toISOString(), userAgent: navigator.userAgent, }; localStorage.setItem( "customTableState", JSON.stringify(enhancedState) ); }, // Row click handler onRowClick: function (rowData, index, event) { console.log("Row clicked:", rowData); }, // Selection change handler onSelectionChange: function (selectedRows) { console.log("Selection changed:", selectedRows.length, "rows"); }, // Error handler onError: function (error) { console.error("Table error:", error); }, }); // Events - Setup AFTER table creation but BEFORE any data loading table.on("initComplete", function (data, meta) { console.log("🎉 initComplete event fired:", data); }); table.on("selectionChange", function (selectedRows) { console.log("🔄 selectionChange event fired:", selectedRows); }); table.on("error", function (error) { console.log("❌ error event fired:", error); }); // Action handlers window.editUser = function (id) { alert(`Edit user with ID: ${id}`); }; window.deleteUser = function (id) { if (confirm("Are you sure you want to delete this user?")) { alert(`Delete user with ID: ${id}`); } }; </script> </body> </html>