first commit
This commit is contained in:
parent
db2697cc73
commit
51f9867614
|
|
@ -0,0 +1,383 @@
|
||||||
|
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 `<i class="ri-expand-up-down-fill" style="cursor: pointer;" data-column-name="${column}"></i>`;
|
||||||
|
} 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 `<i class="ri-arrow-up-s-fill" style="cursor: pointer;" data-column-name="${column}"></i>`;
|
||||||
|
} else {
|
||||||
|
return `<i class="ri-arrow-down-s-fill" style="cursor: pointer;" data-column-name="${column}"></i>`;
|
||||||
|
}
|
||||||
|
} 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 += `<th scope="col">
|
||||||
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
|
${head.value}
|
||||||
|
</div>
|
||||||
|
</th>`;
|
||||||
|
} else {
|
||||||
|
if (head.hasOwnProperty("render")) {
|
||||||
|
ths += `<th scope="col">
|
||||||
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
|
${head.render(head)}
|
||||||
|
${
|
||||||
|
this.config.sort.enable &&
|
||||||
|
this.config.sort.listColumn &&
|
||||||
|
this.config.sort.listColumn.includes(head.name)
|
||||||
|
? this.renderIconSort(head.name)
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</th>`;
|
||||||
|
} else {
|
||||||
|
ths += `<th scope="col">
|
||||||
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
|
${head.value}
|
||||||
|
${
|
||||||
|
this.config.sort.enable &&
|
||||||
|
this.config.sort.listColumn &&
|
||||||
|
this.config.sort.listColumn.includes(head.name)
|
||||||
|
? this.renderIconSort(head.name)
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</th>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var html = `<thead class="table-light text-center align-middle">
|
||||||
|
<tr>
|
||||||
|
${ths}
|
||||||
|
<tr>
|
||||||
|
</thead>`;
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render rows in table
|
||||||
|
renderRows(data) {
|
||||||
|
let html = "<tbody>";
|
||||||
|
data.data.map((row, index) => {
|
||||||
|
html += `<tr id='row_${row.id}'>`;
|
||||||
|
this.config.heads.map((col) => {
|
||||||
|
html += `<td ${
|
||||||
|
col.name !== "__actions" ? `title="${row[col.name]}"` : ""
|
||||||
|
}>${this.config.rowRender(col.name, row[col.name], row)}</td>`;
|
||||||
|
});
|
||||||
|
html += "</tr>";
|
||||||
|
});
|
||||||
|
html += "</tbody>";
|
||||||
|
// Initial pagination use 'data.links'
|
||||||
|
let htmlPagination = `<ul class="pagination">`;
|
||||||
|
data.links.map((link) => {
|
||||||
|
htmlPagination += `
|
||||||
|
<li class="page-item ${link.active ? "active" : ""}">
|
||||||
|
<span class="page_number page-link" data-column-name="${
|
||||||
|
link.url !== null ? link.url.split("=")[1] : null
|
||||||
|
}" style="cursor: pointer;">${link.label
|
||||||
|
.replace(" Previous", "")
|
||||||
|
.replace("Next ", "")}</span>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
htmlPagination += "</ul>";
|
||||||
|
html += `<caption>
|
||||||
|
<div class="d-flex align-items-center" style="justify-content: space-between;">`;
|
||||||
|
html += `<div id="perpage">
|
||||||
|
<!-- Per page -->
|
||||||
|
<div class="d-flex align-items-center form-inline">
|
||||||
|
<label class="mr-2">Show</label>
|
||||||
|
<select id="perPageSelect" class="form-select form-select-sm me-2" style="font-size: 0.8rem; margin: 0 5px; cursor: pointer;">
|
||||||
|
<option value="15" ${
|
||||||
|
this.config.per_page.toString() === "15" ? "selected" : ""
|
||||||
|
}>15</option>
|
||||||
|
<option value="30" ${
|
||||||
|
this.config.per_page.toString() === "30" ? "selected" : ""
|
||||||
|
}>30</option>
|
||||||
|
<option value="50" ${
|
||||||
|
this.config.per_page.toString() === "50" ? "selected" : ""
|
||||||
|
}>50</option>
|
||||||
|
<option value="80" ${
|
||||||
|
this.config.per_page.toString() === "80" ? "selected" : ""
|
||||||
|
}>80</option>
|
||||||
|
<option value="100" ${
|
||||||
|
this.config.per_page.toString() === "100"
|
||||||
|
? "selected"
|
||||||
|
: ""
|
||||||
|
}>100</option>
|
||||||
|
</select>
|
||||||
|
<label style="width: auto;">entries</label>
|
||||||
|
</div>
|
||||||
|
<!-- Per page -->
|
||||||
|
</div>`;
|
||||||
|
if (this.config.footer.detail) {
|
||||||
|
html += `<div id="footer_detail">Show ${data.from} to ${data.to} of ${data.total} entries</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.config.footer.pagination) {
|
||||||
|
html += `<div id="footer_pagination">${htmlPagination}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
html += `</div></caption>`;
|
||||||
|
$(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 `
|
||||||
|
<div class="d-flex" style="justify-content: space-evenly;">
|
||||||
|
<i class="ri-edit-2-fill btn_edit btn btn-primary" style="--bs-btn-padding-y: .15rem; --bs-btn-padding-x: .3rem; --bs-btn-font-size: .75rem;" data-row-id="${row.id}"></i>
|
||||||
|
<i class="ri-check-line btn_done btn btn-success" style="--bs-btn-padding-y: .15rem; --bs-btn-padding-x: .3rem; --bs-btn-font-size: .75rem; display: none;" data-row-id="${row.id}"></i>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define and automatically create editable cells
|
||||||
|
// Used in rowRender configuration
|
||||||
|
cellEdit(colName, colValue) {
|
||||||
|
return `
|
||||||
|
<div class="cell_show"><span class="${colName}">${colValue}</span></div>
|
||||||
|
<div class="cell_edit"><input class="${colName}" style="display: none;" type='text' value='${colValue}'/></div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,183 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>JDataTable</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/remixicon@4.0.1/fonts/remixicon.min.css" />
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="./JDataTable.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container mt-3">
|
||||||
|
<h2>JDataTable</h2>
|
||||||
|
<p>A library used to initialize a basic data table. Includes the main components of a data table such as: sorting, per page, pagination, table. Supports additional configuration of search and filtering features.</p>
|
||||||
|
|
||||||
|
<!-- Filter -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Filter</h5>
|
||||||
|
<form id="filterForm">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">Email:</label>
|
||||||
|
<input type="text" class="form-control" id="email" name="email">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="code">Code:</label>
|
||||||
|
<input type="text" class="form-control" id="code" name="code">
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-primary mt-2" onclick="getFormValues()">Filter</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Filter -->
|
||||||
|
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label for="search_input">Search:</label>
|
||||||
|
<input id="search_input" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
<!-- Search -->
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<table class="table table-striped table-bordered table-hover" id="bookTabe">
|
||||||
|
</table>
|
||||||
|
<!-- Table -->
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div id="pagination"></div>
|
||||||
|
<!-- Pagination -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var config = {
|
||||||
|
// Declare configuration for table headers
|
||||||
|
// 'render' function is used to customize the header
|
||||||
|
heads: [{
|
||||||
|
name: "id",
|
||||||
|
value: "ID",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "email",
|
||||||
|
value: "Email",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "code",
|
||||||
|
value: "Code",
|
||||||
|
render: (heads) => {
|
||||||
|
var html = `
|
||||||
|
<h1>${heads.value}</h1>
|
||||||
|
`;
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "created_at",
|
||||||
|
value: "Created at",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "__actions",
|
||||||
|
value: "Action",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
/* data: data, */ //Use data if config.ajax not exist
|
||||||
|
|
||||||
|
// Used to customize rows according to column names
|
||||||
|
rowRender: (colName, colValue, row) => {
|
||||||
|
switch (colName) {
|
||||||
|
case "id":
|
||||||
|
return `
|
||||||
|
<div class="text-center">
|
||||||
|
${row.id}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
case "email":
|
||||||
|
return tableData.cellEdit(colName, colValue);
|
||||||
|
case "code":
|
||||||
|
return tableData.cellEdit(colName, colValue);
|
||||||
|
case "__actions":
|
||||||
|
return tableData.actionEdit(row);
|
||||||
|
default:
|
||||||
|
return colValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Ajax function to automatically get initial data and re-render times
|
||||||
|
// If this parameter is not present, the library will use the default parameter "data" passed directly
|
||||||
|
ajax: (params) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
$.ajax({
|
||||||
|
url: "https://payment.nswteam.net/api/v1/admin/discount/get",
|
||||||
|
type: "GET",
|
||||||
|
data: params,
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3BheW1lbnQubnN3dGVhbS5uZXQvYXBpL3YxL2FkbWluL2xvZ2luIiwiaWF0IjoxNzA4NDgxMDUwLCJleHAiOjE3MDg1Njc0NTAsIm5iZiI6MTcwODQ4MTA1MCwianRpIjoid0k3alN1OWxlZHJxM3IwSiIsInN1YiI6IjUiLCJwcnYiOiJkMmZmMjkzMzlhOGEzZTgyYzM1ODJhNWE4ZTczOWRmMTc4OWJiMTJmIn0.8aWr2DlfNvQZqBiXIFaDRS8_VsARAl1TEynsuYpZcqY", // Include the token in the request header
|
||||||
|
},
|
||||||
|
success: function (response) {
|
||||||
|
resolve(response);
|
||||||
|
},
|
||||||
|
error: function (error) {
|
||||||
|
console.log(error);
|
||||||
|
reject(error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// Information used to call the API for the row and cell update function
|
||||||
|
apiUpdate: {
|
||||||
|
url: "https://payment.nswteam.net/api/v1/admin/discount/update",
|
||||||
|
type: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3BheW1lbnQubnN3dGVhbS5uZXQvYXBpL3YxL2FkbWluL2xvZ2luIiwiaWF0IjoxNzA4NDgxMDUwLCJleHAiOjE3MDg1Njc0NTAsIm5iZiI6MTcwODQ4MTA1MCwianRpIjoid0k3alN1OWxlZHJxM3IwSiIsInN1YiI6IjUiLCJwcnYiOiJkMmZmMjkzMzlhOGEzZTgyYzM1ODJhNWE4ZTczOWRmMTc4OWJiMTJmIn0.8aWr2DlfNvQZqBiXIFaDRS8_VsARAl1TEynsuYpZcqY", // Include the token in the request header
|
||||||
|
},
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
pagination: true,
|
||||||
|
detail: true
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
enable: true,
|
||||||
|
listColumn: ["id", "email", "code", "created_at"]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial table
|
||||||
|
var tableData = new TableData("#bookTabe", config);
|
||||||
|
tableData.render();
|
||||||
|
|
||||||
|
// Get values from form html and append to config -> re-render with new data
|
||||||
|
const getFormValues = () => {
|
||||||
|
const formData = {};
|
||||||
|
const form = document.getElementById("filterForm");
|
||||||
|
|
||||||
|
for (let i = 0; i < form.elements.length; i++) {
|
||||||
|
const element = form.elements[i];
|
||||||
|
|
||||||
|
if (!element.name || element.tagName === "BUTTON") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
formData[element.name] = element.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.filter = formData;
|
||||||
|
tableData.updateConfig(config);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Search for keywords by line (tr tag)
|
||||||
|
$("#search_input").on("keyup", function () {
|
||||||
|
var value = $(this).val().toLowerCase();
|
||||||
|
$("#bookTabe tbody tr").filter(function () {
|
||||||
|
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
552
index.php
552
index.php
|
|
@ -1,552 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>Bootstrap Example</title>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/remixicon@4.0.1/fonts/remixicon.min.css" />
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="container mt-3">
|
|
||||||
<h2>Striped Rows</h2>
|
|
||||||
<p>The .table-striped class adds zebra-stripes to a table:</p>
|
|
||||||
|
|
||||||
<!-- Filter -->
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">Filter</h5>
|
|
||||||
<form id="filterForm">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="email">Email:</label>
|
|
||||||
<input type="text" class="form-control" id="email" name="email">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="code">Code:</label>
|
|
||||||
<input type="text" class="form-control" id="code" name="code">
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-primary mt-2" onclick="getFormValues()">Filter</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Filter -->
|
|
||||||
|
|
||||||
<!-- Search -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="search_input">Search:</label>
|
|
||||||
<input id="search_input" type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
<!-- Search -->
|
|
||||||
|
|
||||||
<!-- Table -->
|
|
||||||
<table class="table table-striped table-bordered table-hover" id="bookTabe">
|
|
||||||
</table>
|
|
||||||
<!-- Table -->
|
|
||||||
|
|
||||||
<!-- Pagination -->
|
|
||||||
<div id="pagination"></div>
|
|
||||||
<!-- Pagination -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
class TableData {
|
|
||||||
config = {
|
|
||||||
order: null, // example order = { column : "name", orderBy : "ASC" }
|
|
||||||
filter: null, // example filter = { name : "huynh" }
|
|
||||||
heads: [], // config headers of table
|
|
||||||
page: 1,
|
|
||||||
per_page: 15,
|
|
||||||
data: {}, // la data ben laravel tra ve
|
|
||||||
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 `<i class="ri-expand-up-down-fill" style="cursor: pointer;" data-column-name="${column}"></i>`;
|
|
||||||
} 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 `<i class="ri-arrow-up-s-fill" style="cursor: pointer;" data-column-name="${column}"></i>`;
|
|
||||||
} else {
|
|
||||||
return `<i class="ri-arrow-down-s-fill" style="cursor: pointer;" data-column-name="${column}"></i>`;
|
|
||||||
}
|
|
||||||
} 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 += `<th scope="col">
|
|
||||||
<div class="d-flex justify-content-center align-items-center">
|
|
||||||
${head.value}
|
|
||||||
</div>
|
|
||||||
</th>`;
|
|
||||||
} else {
|
|
||||||
if (head.hasOwnProperty("render")) {
|
|
||||||
ths += `<th scope="col">
|
|
||||||
<div class="d-flex justify-content-center align-items-center">
|
|
||||||
${head.render(head)}
|
|
||||||
${this.config.sort.enable &&
|
|
||||||
this.config.sort.listColumn &&
|
|
||||||
this.config.sort.listColumn.includes(head.name) ?
|
|
||||||
this.renderIconSort(head.name) : ''}
|
|
||||||
</div>
|
|
||||||
</th>`;
|
|
||||||
} else {
|
|
||||||
ths += `<th scope="col">
|
|
||||||
<div class="d-flex justify-content-center align-items-center">
|
|
||||||
${head.value}
|
|
||||||
${this.config.sort.enable &&
|
|
||||||
this.config.sort.listColumn &&
|
|
||||||
this.config.sort.listColumn.includes(head.name) ?
|
|
||||||
this.renderIconSort(head.name) : ''}
|
|
||||||
</div>
|
|
||||||
</th>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var html = `<thead class="table-light text-center align-middle">
|
|
||||||
<tr>
|
|
||||||
${ths}
|
|
||||||
<tr>
|
|
||||||
</thead>`;
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render rows in table
|
|
||||||
renderRows(data) {
|
|
||||||
let html = "<tbody>";
|
|
||||||
data.data.map((row, index) => {
|
|
||||||
html += `<tr id='row_${row.id}'>`;
|
|
||||||
this.config.heads.map((col) => {
|
|
||||||
html += `<td ${col.name!=="__actions"?`title="${row[col.name]}"`:""}>${this.config.rowRender(
|
|
||||||
col.name,
|
|
||||||
row[col.name],
|
|
||||||
row
|
|
||||||
)}</td>`;
|
|
||||||
});
|
|
||||||
html += "</tr>";
|
|
||||||
});
|
|
||||||
html += "</tbody>";
|
|
||||||
// Initial pagination use 'data.links'
|
|
||||||
let htmlPagination = `<ul class="pagination">`;
|
|
||||||
data.links.map((link) => {
|
|
||||||
htmlPagination += `
|
|
||||||
<li class="page-item ${link.active ? "active" : ""}">
|
|
||||||
<span class="page_number page-link" data-column-name="${
|
|
||||||
link.url !== null ? link.url.split("=")[1] : null
|
|
||||||
}" style="cursor: pointer;">${link.label
|
|
||||||
.replace(" Previous", "")
|
|
||||||
.replace("Next ", "")}</span>
|
|
||||||
</li>
|
|
||||||
`;
|
|
||||||
});
|
|
||||||
htmlPagination += "</ul>";
|
|
||||||
html += `<caption>
|
|
||||||
<div class="d-flex align-items-center" style="justify-content: space-between;">`
|
|
||||||
html += `<div id="perpage">
|
|
||||||
<!-- Per page -->
|
|
||||||
<div class="d-flex align-items-center form-inline">
|
|
||||||
<label class="mr-2">Show</label>
|
|
||||||
<select id="perPageSelect" class="form-select form-select-sm me-2" style="font-size: 0.8rem; margin: 0 5px; cursor: pointer;">
|
|
||||||
<option value="15" ${this.config.per_page.toString() === "15" ? 'selected' : ''}>15</option>
|
|
||||||
<option value="30" ${this.config.per_page.toString() === "30" ? 'selected' : ''}>30</option>
|
|
||||||
<option value="50" ${this.config.per_page.toString() === "50" ? 'selected' : ''}>50</option>
|
|
||||||
<option value="80" ${this.config.per_page.toString() === "80" ? 'selected' : ''}>80</option>
|
|
||||||
<option value="100" ${this.config.per_page.toString() === "100" ? 'selected' : ''}>100</option>
|
|
||||||
</select>
|
|
||||||
<label style="width: auto;">entries</label>
|
|
||||||
</div>
|
|
||||||
<!-- Per page -->
|
|
||||||
</div>`
|
|
||||||
if (this.config.footer.detail) {
|
|
||||||
html += `<div id="footer_detail">Show ${data.from} to ${data.to} of ${data.total} entries</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.config.footer.pagination) {
|
|
||||||
html += `<div id="footer_pagination">${htmlPagination}</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
html += `</div></caption>`
|
|
||||||
$(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 `
|
|
||||||
<div class="d-flex" style="justify-content: space-evenly;">
|
|
||||||
<i class="ri-edit-2-fill btn_edit btn btn-primary" style="--bs-btn-padding-y: .15rem; --bs-btn-padding-x: .3rem; --bs-btn-font-size: .75rem;" data-row-id="${row.id}"></i>
|
|
||||||
<i class="ri-check-line btn_done btn btn-success" style="--bs-btn-padding-y: .15rem; --bs-btn-padding-x: .3rem; --bs-btn-font-size: .75rem; display: none;" data-row-id="${row.id}"></i>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define and automatically create editable cells
|
|
||||||
// Used in rowRender configuration
|
|
||||||
cellEdit(colName, colValue) {
|
|
||||||
return `
|
|
||||||
<div class="cell_show"><span class="${colName}">${colValue}</span></div>
|
|
||||||
<div class="cell_edit"><input class="${colName}" style="display: none;" type='text' value='${colValue}'/></div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = {
|
|
||||||
// Declare configuration for table headers
|
|
||||||
// 'render' function is used to customize the header
|
|
||||||
heads: [{
|
|
||||||
name: "id",
|
|
||||||
value: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "email",
|
|
||||||
value: "Email",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "code",
|
|
||||||
value: "Code",
|
|
||||||
render: (heads) => {
|
|
||||||
var html = `
|
|
||||||
<h1>${heads.value}</h1>
|
|
||||||
`;
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "created_at",
|
|
||||||
value: "Created at",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "__actions",
|
|
||||||
value: "Action",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
/* data: data, */ //Use data if config.ajax not exist
|
|
||||||
|
|
||||||
// Used to customize rows according to column names
|
|
||||||
rowRender: (colName, colValue, row) => {
|
|
||||||
switch (colName) {
|
|
||||||
case "id":
|
|
||||||
return `
|
|
||||||
<div class="text-center">
|
|
||||||
${row.id}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
case "email":
|
|
||||||
return tableData.cellEdit(colName, colValue);
|
|
||||||
case "code":
|
|
||||||
return tableData.cellEdit(colName, colValue);
|
|
||||||
case "__actions":
|
|
||||||
return tableData.actionEdit(row);
|
|
||||||
default:
|
|
||||||
return colValue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Ajax function to automatically get initial data and re-render times
|
|
||||||
// If this parameter is not present, the library will use the default parameter "data" passed directly
|
|
||||||
ajax: (params) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
$.ajax({
|
|
||||||
url: "https://payment.nswteam.net/api/v1/admin/discount/get",
|
|
||||||
type: "GET",
|
|
||||||
data: params,
|
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3BheW1lbnQubnN3dGVhbS5uZXQvYXBpL3YxL2FkbWluL2xvZ2luIiwiaWF0IjoxNzA4NDgxMDUwLCJleHAiOjE3MDg1Njc0NTAsIm5iZiI6MTcwODQ4MTA1MCwianRpIjoid0k3alN1OWxlZHJxM3IwSiIsInN1YiI6IjUiLCJwcnYiOiJkMmZmMjkzMzlhOGEzZTgyYzM1ODJhNWE4ZTczOWRmMTc4OWJiMTJmIn0.8aWr2DlfNvQZqBiXIFaDRS8_VsARAl1TEynsuYpZcqY", // Include the token in the request header
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
resolve(response);
|
|
||||||
},
|
|
||||||
error: function(error) {
|
|
||||||
console.log(error);
|
|
||||||
reject(error);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// Information used to call the API for the row and cell update function
|
|
||||||
apiUpdate: {
|
|
||||||
url: "https://payment.nswteam.net/api/v1/admin/discount/update",
|
|
||||||
type: "POST",
|
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3BheW1lbnQubnN3dGVhbS5uZXQvYXBpL3YxL2FkbWluL2xvZ2luIiwiaWF0IjoxNzA4NDgxMDUwLCJleHAiOjE3MDg1Njc0NTAsIm5iZiI6MTcwODQ4MTA1MCwianRpIjoid0k3alN1OWxlZHJxM3IwSiIsInN1YiI6IjUiLCJwcnYiOiJkMmZmMjkzMzlhOGEzZTgyYzM1ODJhNWE4ZTczOWRmMTc4OWJiMTJmIn0.8aWr2DlfNvQZqBiXIFaDRS8_VsARAl1TEynsuYpZcqY", // Include the token in the request header
|
|
||||||
},
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
pagination: true,
|
|
||||||
detail: true
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
enable: true,
|
|
||||||
listColumn: ["id", "email", "code", "created_at"]
|
|
||||||
},
|
|
||||||
order: {
|
|
||||||
order_by_id: 'desc'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initial table
|
|
||||||
var tableData = new TableData("#bookTabe", config);
|
|
||||||
tableData.render();
|
|
||||||
|
|
||||||
// Get values from form html and append to config -> re-render with new data
|
|
||||||
const getFormValues = () => {
|
|
||||||
const formData = {};
|
|
||||||
const form = document.getElementById("filterForm");
|
|
||||||
|
|
||||||
for (let i = 0; i < form.elements.length; i++) {
|
|
||||||
const element = form.elements[i];
|
|
||||||
|
|
||||||
if (!element.name || element.tagName === "BUTTON") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
formData[element.name] = element.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.filter = formData;
|
|
||||||
tableData.updateConfig(config);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Search for keywords by line (tr tag)
|
|
||||||
$("#search_input").on("keyup", function() {
|
|
||||||
var value = $(this).val().toLowerCase();
|
|
||||||
$("#bookTabe tbody tr").filter(function() {
|
|
||||||
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
Loading…
Reference in New Issue