Example 1: Basic Table with Sorting and Filtering
ตัวอย่าง table พื้นฐานที่มีการ sort และ filter พร้อม pagination
| ID | Name | Position | Department | Status |
|---|
HTML Code:
<table class="table border fullwidth" data-table="basic-table" data-source="data/example-table-data.json"
data-page-size="10">
<thead>
<tr>
<th data-field="id" data-sort="id">ID</th>
<th data-field="name" data-sort="name" data-filter="true" data-type="text">Name</th>
<th data-field="position" data-format="lookup" data-sort="position"
data-options='{"1":"Programmer","2":"Systems Analyst","3":"Project Manager","4":"QA
Tester","5":"UI/UX
Designer","6":"Sales","7":"Marketer","8":"Accountant","9":"HR Officer"}'>
Position</th>
<th data-field="department" data-format="lookup" data-filter="true" data-type="select"
data-show-all="true" class="center"
data-options='{"1":"Engineering","2":"Business Analysis","3":"Project
Management","4":"QA","5":"UI/UX","6":"Sales","7":"Marketing","8":"Accounting","9":"Human
Resources"}'>
Department</th>
<th data-field="status" data-sort="status" data-filter="true" data-type="select" data-format="lookup"
data-show-all="true" class="center" data-cell-class="right"
data-options='{"1":"Working","2":"On
Leave","3":"Resigned","4":"Probation"}'>
Status</th>
</tr>
</thead>
<tbody></tbody>
</table>
- Static HTML: ใช้
classattribute ปกติสำหรับ <th>, ใช้data-cell-classสำหรับ <td> - Dynamic Columns (API): ใช้
classสำหรับ <th>, ใช้cellClassสำหรับ <td> - แยกกันเด็ดขาด ไม่มี fallback ระหว่าง th และ td
Example 2: Checkboxes and Bulk Actions
Table พร้อม checkboxes สำหรับเลือกแถวและทำ bulk actions
| Name | Department | Status | Salary |
|---|
HTML Code:
<table data-table="bulk-actions-table"
data-source="data/example-table-data.json"
data-show-checkbox="true"
data-actions='{"delete":"Delete","activate":"Activate"}'
data-action-url="api/bulk-action"
data-action-button="Process Selected">
<!-- table content -->
</table>
JavaScript:
// Listen to action completion
document.addEventListener('table:action-complete', (e) => {
const {tableId, action, items, response} = e.detail;
console.log(`${action} completed for ${items.length} items`);
// Reload table data
TableManager.loadTableData(tableId);
});
Example 3: Row Actions with Dropdown Menu
Table พร้อม dropdown menu สำหรับ row actions - ใช้ submenu configuration
| ID | Name | Position | Status |
|---|
HTML Code:
<table data-table="row-actions-table"
data-source="data/example-table-data.json"
data-row-actions='{
"view": {
"label": "View",
"className": "btn btn-info icon-published1"
},
"actions": {
"label": "Actions",
"className": "btn btn-primary dropdown icon-menu",
"submenu": {
"edit": {
"label": "Edit",
"className": "icon-edit"
},
"delete": {
"label": "Delete",
"className": "color-red icon-delete"
}
}
}
}'>
<thead>
<tr>
<th data-field="name">Name</th>
<th data-field="email">Email</th>
</tr>
</thead>
<tbody></tbody>
</table>
Note:
Split Button: ใช้ submenu configuration เพื่อสร้าง split button โดยมีปุ่ม
View เป็นปุ่มหลัก และปุ่ม Actions dropdown (hover) ที่มี Edit และ Delete
ใน submenu
Example 4: Server-Side Pagination and Filtering
Table ที่โหลดข้อมูลจาก API พร้อม server-side pagination, sorting และ filtering
| ID | Name | Phone | Status | Created | Last Visit |
|---|
HTML Code:
<table data-table="server-side-table"
data-source="api/v1/users"
data-page-size="10"
data-url-params="true">
<thead>
<tr>
<th data-field="name" data-sort="name" data-filter="true">Name</th>
<th data-field="status" data-filter="true" data-type="select">Status</th>
</tr>
</thead>
</table>
Expected API Response:
{
"success": true,
"data": [
{"id": 1, "name": "John Doe", "email": "john@example.com"},
{"id": 2, "name": "Jane Smith", "email": "jane@example.com"}
],
"meta": {
"total": 1000,
"totalPages": 40,
"currentPage": 1,
"pageSize": 10
},
"filters": {
"status": [
{"value": "1", "text": "Active"},
{"value": "0", "text": "Inactive"}
]
}
}
Example 5: Table with Date Formatting
Table ที่แสดงข้อมูลพร้อม date formatting และ number formatting
| ID | Name | Position | Status | Join Date | Salary |
|---|
HTML Code:
<table data-table="inline-edit-table"
data-source="data/example-table-data.json">
<thead>
<tr>
<th data-field="name" data-sort="name">Name</th>
<th data-field="joinDate" data-format="date">Join Date</th>
<th data-field="salary" data-format="number">Salary</th>
</tr>
</thead>
</table>
Available Formats:
// data-format options:
// - "lookup": แปลงค่าตาม data-options
// - "date": แสดงวันที่ (YYYY-MM-DD → DD/MM/YYYY)
// - "datetime": แสดงวันที่และเวลา
// - "number": แสดงตัวเลขพร้อม comma separator
// - "currency": แสดงเงิน (ต้องระบุ currency ใน config)
Example 6: Table Footer with Aggregates
Table พร้อม footer ที่แสดงค่ารวม, ค่าเฉลี่ย, และการนับ
| ID | Name | Position | Department | Salary | Join Date |
|---|
HTML Code:
<table data-table="footer-table"
data-show-footer="true"
data-footer-aggregates='{"salary":"sum","id":"count"}'>
<thead>
<tr>
<th data-field="id">ID</th>
<th data-field="salary" data-format="number">Salary</th>
</tr>
</thead>
<tfoot></tfoot>
</table>
JavaScript Initialization:
await TableManager.init({
showFooter: true,
footerAggregates: {
salary: 'sum', // แสดงผลรวม
quantity: 'sum',
rating: 'avg', // แสดงค่าเฉลี่ย
id: 'count' // นับจำนวน
}
});
Example 7: Client-Side Data Management
Table ที่ใช้ข้อมูลฝั่ง client โดยไม่ต้องเรียก API
| ID | Product | Category | Price | Stock |
|---|
JavaScript Code:
// Client-side data
const products = [
{ id: 1, product: 'Laptop', category: 'Electronics', price: 999, stock: 50 },
{ id: 2, product: 'Mouse', category: 'Accessories', price: 25, stock: 200 },
{ id: 3, product: 'Keyboard', category: 'Accessories', price: 75, stock: 150 }
];
// Set data to table
TableManager.setData('client-side-table', products);
// Add new row
const newProduct = {
id: products.length + 1,
product: 'Monitor',
category: 'Electronics',
price: 299,
stock: 75
};
products.push(newProduct);
TableManager.setData('client-side-table', products);
// Get all data
const allData = TableManager.getData('client-side-table');
// Get filtered data
const filteredData = TableManager.getData('client-side-table', true);
Example 8: Export Data
Export table data เป็น CSV, Excel, หรือ JSON
| ID | Name | Department | Status | Salary |
|---|
JavaScript Code:
// Export to CSV
document.getElementById('exportCSV').addEventListener('click', () => {
TableManager.exportData('export-table', 'csv', {
filename: 'employees.csv'
});
});
// Export to Excel (server-side)
document.getElementById('exportExcel').addEventListener('click', () => {
TableManager.exportData('export-table', 'excel', {
filename: 'employees.xlsx'
});
});
// Export to JSON
document.getElementById('exportJSON').addEventListener('click', () => {
TableManager.exportData('export-table', 'json', {
filename: 'employees.json'
});
});
// Export filtered data only
document.getElementById('exportFiltered').addEventListener('click', () => {
TableManager.exportData('export-table', 'csv', {
filename: 'filtered_employees.csv',
filtered: true
});
});
Example 9: Filter Actions (Table-level Actions)
ปุ่มและลิงค์ที่ส่ง filter parameters ไปยัง action URL - สำหรับ export, report generation, หรือ bulk operations
| ID | Name | Department | Status | Salary |
|---|
HTML Code:
<table data-table="filter-actions-table"
data-source="api/users"
data-filter-actions='{
"export": {
"label": "Export Filtered",
"url": "api/export",
"type": "button",
"className": "btn-primary"
},
"report": {
"label": "View Report",
"url": "/reports",
"type": "link",
"className": "btn-info",
"target": "_blank"
}
}'>
<!-- table content -->
</table>
Filter Actions Options:
// data-filter-actions configuration
{
"actionKey": {
"label": "Button Text", // ข้อความบน button/link
"url": "api/action", // URL สำหรับ action (required)
"type": "button", // "button" (POST) หรือ "link" (GET redirect)
"className": "btn-primary icon-xxx", // CSS classes
"target": "_self", // สำหรับ link: "_blank" เปิด tab ใหม่
"confirm": "Are you sure?" // ข้อความยืนยัน (optional)
}
}
// Button จะส่ง POST request:
{
"action": "export",
"tableId": "filter-actions-table",
"filters": {"status": "1", "department": "5"},
"sort": {"name": "asc"}
}
// Link จะ redirect ไปยัง:
// /reports?status=1&department=5
Event Listener:
// Listen to filter action events
document.addEventListener('table:filterAction', (e) => {
const {tableId, action, type, params, response} = e.detail;
console.log(`Filter action: ${action} (${type})`);
console.log('Filters:', params);
});
Example 10: Row Drag & Editable Rows
สาธิตการเปิด/ปิดการลากแถวด้วย drag handle (แสดงเมื่อแก้ไขแถวได้) พร้อม UX ล่าสุด: ghost เป็นไอคอนเล็กติดเคอร์เซอร์, placeholder เส้นประ และล็อกการลากแนวตั้ง
| ID | Name | Department | Status | Salary |
|---|
JavaScript Toggle:
const tableId = 'row-sortable-table';
document.getElementById('enableRowSort').onclick = () => TableManager.enableRowSort(tableId);
document.getElementById('disableRowSort').onclick = () => TableManager.disableRowSort(tableId);
document.getElementById('resetRowOrder').onclick = () => TableManager.loadTableData(tableId);
// Drag handles appear only when allowRowModification is true.
// Dragging is vertical-only with dashed placeholder and icon ghost at cursor.
Example 11: Cell Elements (ElementManager)
เรนเดอร์ input/select/textarea ในเซลล์ด้วย data-cell-element (หรือ data-type shorthand)
พร้อม config ส่งต่อไปยัง ElementManager
| Name | Status |
|---|
Key Attributes:
data-cell-elementหรือdata-type(shorthand) เลือกชนิด controldata-optionsสำหรับ select,data-allow-emptyเพื่อแสดงตัวเลือกว่างdata-max-lengthใช้เมื่อค่ามากกว่า 0 เท่านั้น
Example 12: Dynamic Table Columns
Table headers generated automatically from API column metadata - perfect for multi-language tables or dynamic schemas
HTML Code:
<table data-table="dynamic-columns-table"
data-source="api/languages"
data-dynamic-columns="true">
<!-- NO thead needed - generated from API -->
<tbody></tbody>
</table>
API Response Format:
{
"columns": [
{
"field": "id",
"label": "ID",
"sort": "id",
"type": "number",
"i18n": true
},
{
"field": "key",
"label": "Key",
"sort": "key",
"searchable": true,
"i18n": true
},
{
"field": "th",
"label": "TH",
"sort": "th",
"searchable": true,
"i18n": true
},
{
"field": "en",
"label": "EN",
"sort": "en",
"searchable": true,
"i18n": true
}
],
"data": [
{"id": 1, "key": "Hello", "th": "สวัสดี", "en": "Hello"},
{"id": 2, "key": "Goodbye", "th": "ลาก่อน", "en": "Goodbye"}
]
}
PHP Example:
// Auto-detect language columns from database
$columns = [
['field' => 'id', 'label' => 'ID', 'sort' => 'id', 'type' => 'number'],
['field' => 'key', 'label' => 'Key', 'sort' => 'key', 'searchable' => true]
];
$language = \Kotchasan\DB::create()->first('language');
foreach ($language as $key => $value) {
if (!in_array($key, ['id', 'key', 'type', 'js'])) {
$columns[] = [
'field' => $key,
'label' => strtoupper($key),
'sort' => $key,
'searchable' => true
];
}
}
return ['columns' => $columns, 'data' => $data];
Benefits:
- ✅ Zero HTML Changes: เพิ่ม/ลด คอลัมน์โดยไม่แก้ template
- ✅ Multi-Language Support: เหมาะสำหรับตารางที่มีหลายภาษา
- ✅ Database-Driven: อ่านโครงสร้างจากฐานข้อมูลอัตโนมัติ
- ✅ Full Features: รองรับ sort, filter, search, validation ครบทุกอย่าง
Column Styling with class and cellClass:
แยกการกำหนด CSS class ระหว่าง header และ body cells:
{
"columns": [
{
"field": "id",
"label": "ID",
"class": "header-mono", // CSS class for <th> only
"cellClass": "mono small" // CSS class for <td> only
},
{
"field": "name",
"label": "Name",
"class": "header-bold",
"cellClass": "text-bold"
},
{
"field": "status",
"label": "Status",
"cellClass": "badge text-center" // Only td gets class
}
]
}
classattribute ใช้กับ<th>เท่านั้นcellClassattribute ใช้กับ<td>เท่านั้น- ทั้งสองแยกกันเด็ดขาด ไม่มี fallback
- สามารถกำหนดแค่ตัวใดตัวหนึ่ง หรือทั้งคู่ก็ได้
Use Cases:
- Language Tables: เพิ่ม/ลด ภาษาได้โดยแค่ ALTER TABLE
- Custom Fields: Schema ที่ผู้ใช้กำหนดเองได้
- Multi-Tenant: แต่ละ tenant มี columns ต่างกัน
- Report Tables: Columns ขึ้นอยู่กับ report type
TableManager Initialization
Global initialization และ configuration สำหรับทุก table
Basic Initialization:
// เริ่มต้น TableManager
await TableManager.init({
pageSizes: [10, 25, 50, 100],
urlParams: true,
showCheckbox: false,
confirmDelete: true
});
Complete Configuration:
await TableManager.init({
debug: false, // เปิด debug logging
urlParams: true, // บันทึก state ลง URL
pageSizes: [10, 25, 50, 100], // ตัวเลือก page sizes
showCaption: true, // แสดง table caption
showCheckbox: false, // แสดง checkboxes
showFooter: false, // แสดง footer
footerAggregates: {}, // Footer calculations
searchColumns: [], // Columns สำหรับค้นหา
persistColumnWidths: true, // บันทึกความกว้าง columns
allowRowModification: false, // อนุญาต inline editing
confirmDelete: true, // ยืนยันก่อนลบ
source: '', // Default data source
actionUrl: '', // URL สำหรับ bulk actions
actionButton: 'Process' // Label ของปุ่ม action
});
Event Handling
TableManager emit events สำหรับ tracking และ custom handling
// Table loaded
document.addEventListener('table:loaded', (e) => {
const {tableId, data, meta} = e.detail;
console.log(`Table ${tableId} loaded with ${data.length} records`);
});
// Table sorted
document.addEventListener('table:sorted', (e) => {
const {tableId, field, direction} = e.detail;
console.log(`Sorted by ${field} ${direction}`);
});
// Table filtered
document.addEventListener('table:filtered', (e) => {
const {tableId, filters} = e.detail;
console.log('Active filters:', filters);
});
// Page changed
document.addEventListener('table:page-changed', (e) => {
const {tableId, page, pageSize} = e.detail;
console.log(`Page changed to ${page}`);
});
// Selection changed
document.addEventListener('table:selection-changed', (e) => {
const {tableId, selected, count} = e.detail;
console.log(`${count} rows selected`);
});
// Field changed (inline editing)
document.addEventListener('table:field-changed', (e) => {
const {tableId, field, value, oldValue, rowData, success} = e.detail;
if (success) {
console.log(`${field} updated successfully`);
}
});
// Bulk action complete
document.addEventListener('table:action-complete', (e) => {
const {tableId, action, items, response} = e.detail;
console.log(`${action} completed for ${items.length} items`);
});