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();
}
}