class TableData { config = { order: null, filter: null, heads: [], page: 1, per_page: 15, data: {}, rowRender: (colName, colValue, row) => { return colValue; }, footer: { pagination: false, detail: false, }, sort: { enable: false, listColumn: [], }, }; constructor(tableId, config) { this.config = { ...this.config, ...config, }; this.tableId = tableId; } // Update configuration, display data after sorting, listen again for appropriate icon sorted(column) { if ( this.config.order !== null && Object.values(this.config.order)[0] === "asc" ) { this.config.order = null; this.updateConfig(this.config); } else { if (this.config.order === null) { this.config.order = { [`order_by_${column}`]: "desc", }; this.updateConfig(this.config); this.attachSortEventListeners(".ri-arrow-down-s-fill"); } else { this.config.order = { [`order_by_${column}`]: "asc", }; this.updateConfig(this.config); this.attachSortEventListeners(".ri-arrow-up-s-fill"); } } } // Listen events of sort buttons attachSortEventListeners(className) { const icons = document.querySelectorAll(className); icons.forEach((icon) => { icon.addEventListener("click", (event) => { const columnName = event.target.dataset.columnName; this.sorted(columnName, icon); }); }); } // Show the sort icon again when the sort button is clicked renderIconSort(column) { if (this.config.order === null) { return ``; } else { var orderKey = Object.keys(this.config.order)[0]; var orderValue = Object.values(this.config.order)[0]; if (orderKey === `order_by_${column}`) { if (orderValue === "asc") { return ``; } else { return ``; } } else { return ""; } } } // Listen events of per page attachPerPageEventListeners() { const elements = document.querySelectorAll( `${this.tableId} #perpage div #perPageSelect` ); elements[0].addEventListener("change", (event) => { const value = event.target.value; this.config.per_page = value; this.render(); }); } // Listen events of pagination buttons attachPaginationEventListeners() { const pages = document.querySelectorAll(".page_number"); pages.forEach((page) => { page.addEventListener("click", (event) => { const pageNumber = event.target.dataset.columnName; if (pageNumber !== "null" && pageNumber !== this.config.page) { this.config.page = pageNumber; this.render(); } }); }); } // Listen events of action buttons attachActionEventListeners(className) { const buttons = document.querySelectorAll(className); buttons.forEach((btn) => { btn.addEventListener("click", (event) => { const rowId = event.target.dataset.rowId; if (rowId) { if (className === ".btn_edit") { this.rowEdit(rowId); } if (className === ".btn_done") { this.rowEditDone(rowId); } } }); }); } // Render headers in table renderHeads() { var ths = ""; this.config.heads.map((head) => { if (head.name === "__actions") { ths += `
${head.value}
`; } else { if (head.hasOwnProperty("render")) { ths += `
${head.render(head)} ${ this.config.sort.enable && this.config.sort.listColumn && this.config.sort.listColumn.includes(head.name) ? this.renderIconSort(head.name) : "" }
`; } else { ths += `
${head.value} ${ this.config.sort.enable && this.config.sort.listColumn && this.config.sort.listColumn.includes(head.name) ? this.renderIconSort(head.name) : "" }
`; } } }); var html = ` ${ths} `; return html; } // Render rows in table renderRows(data) { let html = ""; data.data.map((row, index) => { html += ``; this.config.heads.map((col) => { html += `${this.config.rowRender(col.name, row[col.name], row)}`; }); html += ""; }); html += ""; // Initial pagination use 'data.links' let htmlPagination = `"; html += `
`; html += `
`; if (this.config.footer.detail) { html += ``; } if (this.config.footer.pagination) { html += ``; } html += `
`; $(this.tableId).append(html); this.attachPaginationEventListeners(); this.attachPerPageEventListeners(); } // Render table async render() { let data; let params = { per_page: this.config.per_page, page: this.config.page, }; // Clear html $(this.tableId).html(""); // Initial headers $(this.tableId).append(this.renderHeads()); this.attachSortEventListeners(".ri-expand-up-down-fill"); // Append 'order' and 'filter' into params if exist if (this.config.hasOwnProperty("ajax")) { if (this.config.order !== null) { Object.assign(params, this.config.order); } if (this.config.filter !== null) { Object.assign(params, this.config.filter); } // Call ajax and render data data = await this.config.ajax(params); this.renderRows(data); } else { // Use data transmitted directly data = this.config.data; this.renderRows(data); } // Start listening to events of already initialized buttons this.attachActionEventListeners(".btn_edit"); this.attachActionEventListeners(".btn_done"); } // Get the current configuration of the table getConfig() { return this.config; } // Automatically merger new config and re-render updateConfig(newConfig) { this.config = { ...this.config, ...newConfig, }; this.render(); } // Define and automatically create edit buttons // Used in rowRender configuration actionEdit(row) { return `
`; } // Define and automatically create editable cells // Used in rowRender configuration cellEdit(colName, colValue) { return `
${colValue}
`; } // Works when the edit button is clicked rowEdit(rowId) { this.config.heads.map((col) => { var cellShow = $(`#row_${rowId} .cell_show .${col.name}`); var cellEdit = $(`#row_${rowId} .cell_edit .${col.name}`); if (cellShow) { cellShow.hide(); } if (cellEdit) { cellEdit.show(); } }); $(`#row_${rowId} div .btn_done`).show(); $(`#row_${rowId} div .btn_edit`).hide(); } rowEditDone(rowId) { // Initial params with row id let params = { id: parseInt(rowId), }; // Get api update info let apiUpdateInfo = this.config.apiUpdate; // Add edited values ​​to params this.config.heads.map((col) => { var cellEdit = $(`#row_${rowId} .cell_edit .${col.name}`); if (cellEdit.val()) { Object.assign(params, { [col.name]: cellEdit.val(), }); } }); // Call API update data row if (this.config.hasOwnProperty("apiUpdate")) { $.ajax({ url: apiUpdateInfo.url, type: apiUpdateInfo.type, data: params, headers: apiUpdateInfo.headers, success: (response) => { // alert("Edit success"); this.render(); }, error: function (error) { console.log(error); alert("Edit Fail"); }, }); } else { alert("Missing updated API information"); } // $(`#row_${rowId} div .btn_done`).hide(); $(`#row_${rowId} div .btn_edit`).show(); } // Update config and render when change per page changePerPage() { this.config.per_page = $(`${this.tableId} #perPageSelect`).val(); this.render(); } }