NX.NexaDom
— pagination & list
Komponen pagination dengan pencarian, filter, sorting, dan integrasi
config (Office) atau storage (tabel SQL / NexaModels).
Deskripsi
NexaDom menyediakan pagination fleksibel untuk menampilkan data dengan
pencarian, filter, sorting, dan navigasi halaman. Dapat diintegrasikan dengan storage
yang ada (Office lewat config atau tabel SQL lewat storage).
Fitur utama
- Pagination — First, Prev, Next, Last
- Pencarian real-time dengan debounce (300ms)
- Filter per field
- Sorting ASC/DESC dengan toggle
- Items per page (localStorage)
- State halaman di localStorage
renderopsional atau aksesdataDom.response- Spinner
NexaSpinner/NX.spinner(opsional) - Property
nountuk nomor urut per baris - Sumber
storage—NX.Storage().model("tabel")
Instalasi & penggunaan
Import
const dataDom = new NX.NexaDom({ ... });Penggunaan dasar (tanpa render)
const app = {
alias: [
"user.status AS status",
"user.nama AS nama",
"user.jabatan AS jabatan",
"user.avatar AS avatar",
"user.id AS id",
],
aliasNames: ["status", "nama", "jabatan", "avatar", "id"],
tabelName: ["user"],
where: false,
group: false,
order: false,
operasi: {
user: {
type: "single",
index: "",
aliasIndex: "user",
keyIndex: 261760199266386,
target: "",
condition: "",
aliasTarget: "",
keyTarget: "",
},
},
access: "public",
};
const dataDom = new NX.NexaDom({
container: "#dataContainer",
pagination: "#itempagination",
sortOrder: "ASC",
sortBy: "id",
paginationinfo: "#info",
searchElement: "#itemsearch",
searchFields: ["nama"],
order: 5,
config: app,
});
let template = "";
dataDom.response.forEach((user) => {
template += `
<div class="user-item">
<h3>${user.nama}</h3>
<p>Jabatan: ${user.jabatan}</p>
</div>
`;
});
return `
<input type="search" id="itemsearch" class="form-control">
<div id="dataContainer">${template}</div>
<div id="itempagination"></div>
<div id="info"></div>
`;
(Contoh di atas memakai template string; di HTML dokumen ini tag div di-escape sebagai
<…> agar valid.)
Dengan render (opsional)
const dataDom = new NX.NexaDom({
container: "#dataContainer",
pagination: "#pagination",
order: 10,
config: {
alias: ["user.nama AS nama", "user.email AS email"],
aliasNames: ["nama", "email"],
tabelName: ["user"],
operasi: { user: "SELECT" },
},
render: (dataArray) =>
dataArray
.map(
(item) => `
<div><span>${item.no}</span> <span>${item.nama}</span> <span>${item.email}</span></div>
`
)
.join(""),
});Konfigurasi options
Constructor options
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
pagination / elementBy |
string | #pagination |
Selector container pagination |
container |
string | #dataContainer |
Selector container data |
paginationinfo |
string | null | Info pagination |
searchElement |
string | null | Input search |
sortClickElement / sortCklik |
string | null | Tombol toggle sort |
render |
function | null | Render custom; argumen dataArray (sudah ada no) |
itemsPerPage / order |
number | 10 | Item per halaman |
maxVisiblePages |
number | 5 | Maks. nomor halaman terlihat |
dataLoader |
function | StorageData | Loader data (default jika pakai config) |
onPageChange |
function | null | (currentPage, data) |
onAfterRender |
function | null | (data, container) |
searchKeyword |
string | '' | Keyword awal |
searchFields |
array | [] | Field untuk search |
filterValue / filterField |
string | '' | Filter |
sortBy / sortOrder |
string | id / DESC |
Sorting |
showFirstLast / showPrevNext / showInfo |
boolean | true | Kontrol UI pagination |
config |
object | {} | Query Office / alias (bukan queryConfig di ctor) |
storage |
object | — | Alternatif: NexaModels / tabel SQL — lihat bawah |
spinner |
object | false | — | NexaSpinner; false menonaktifkan |
Catatan: gunakan config (bukan queryConfig) saat init;
gunakan order (bukan itemsPerPage) untuk ukuran halaman.
storage dan config adalah dua jalur berbeda — pilih sesuai backend.
Spinner loading (NexaSpinner)
Depth counter untuk operasi async bersarang. Default aktif; nonaktif dengan
spinner: false atau spinner: { enabled: false }. Tanpa NexaSpinner,
pagination bisa memakai Bootstrap spinner-border.
| Properti | Default | Deskripsi |
|---|---|---|
enabled |
true | Aktif/nonaktif |
centerScreen |
true | Overlay layar penuh vs inline di container |
type |
overlay | overlay | inline | button |
size |
medium | small | medium | large |
color |
#007bff | Warna arc |
message |
'' | Teks opsional |
Referensi: assets/modules/Dom/NexaSpinner.js. Instance memiliki
showSpinner() / hideSpinner() untuk alur kustom.
new NX.NexaDom({
container: "#exsampel-data",
pagination: "#exsampel-pagination",
spinner: {
enabled: true,
centerScreen: true,
type: "overlay",
size: "medium",
color: "#CB2F2F",
},
});Sumber data: opsi storage (NexaModels)
Memuat baris dari tabel SQL lewat NX.Storage().model(namaTabel) — sama seperti
dokumentasi NexaModels (bukan models("ClassPhp")). Loader internal:
storageModelStorageData / NX.StorageModelData.
| Properti | Deskripsi |
|---|---|
model (string) |
Wajib — nama tabel SQL |
select |
Opsional; default "*" — argumen .select() |
query (q) => q |
Hook setelah select: where, join, dll. Dipakai untuk count
dan data per halaman; lalu search NexaDom, filter, orderBy.
|
new NX.NexaDom({
container: "#exsampel-data",
pagination: "#exsampel-pagination",
paginationinfo: "#exsampel-info",
searchElement: "#exsampel-search",
sortClickElement: "#exsampel-sort",
order: 5,
sortBy: "title",
sortOrder: "ASC",
searchFields: ["title", "slug"],
storage: {
model: "demo",
query: (q) => q.whereNotNull("id"),
},
render: (dataArray) => {
/* … */
},
});Struktur config (queryConfig)
{
alias: ["user.nama AS nama", "user.email AS email"],
aliasNames: ["nama", "email"],
tabelName: ["user"],
where: false,
group: false,
order: false,
operasi: { user: "SELECT" },
access: "public",
subquery: "",
subnested: "",
}{
alias: ["user.status AS status", "user.nama AS nama", "user.id AS id"],
aliasNames: ["status", "nama", "id"],
tabelName: ["user"],
where: false,
group: false,
order: false,
operasi: {
user: {
type: "single",
index: "",
aliasIndex: "user",
keyIndex: 261760199266386,
target: "",
condition: "",
aliasTarget: "",
keyTarget: "",
},
},
access: "public",
id: data.id,
}Methods API
Static
NexaDom.create(options) — Promise<NexaDom>, init async. Biasanya
new NexaDom() sudah memicu loadRealDataAndUpdate() non-blocking.
const pagination = await NexaDom.create({
container: "#dataContainer",
pagination: "#pagination",
order: 20,
});Instance
init()— pagination, load data, event listenersloadData()— load dari dataLoadergoToPage(page)— navigasi halamanupdateSearch(keyword, fields),updateFilter(value, field),updateSort(by, order)updateItemsPerPage(n),refresh(showLoading?)getState(),getData(),savePageState(page)destroy()— bersihkan listener + spinner internalshowSpinner()/hideSpinner()
Contoh lanjutan (search, filter, custom loader)
Search & sort
const dataDom = new NX.NexaDom({
container: "#dataContainer",
pagination: "#pagination",
paginationinfo: "#paginationInfo",
searchElement: "#searchInput",
sortClickElement: "#sortButton",
order: 20,
searchFields: ["nama", "email"],
sortBy: "nama",
sortOrder: "ASC",
config: {
alias: ["user.nama AS nama", "user.email AS email"],
aliasNames: ["nama", "email"],
tabelName: ["user"],
operasi: { user: "SELECT" },
},
render: (dataArray) =>
dataArray
.map(
(item) => `
<div class="card"><div>No: ${item.no}</div><div>${item.nama}</div></div>
`
)
.join(""),
onPageChange: (page, data) => console.log("Page:", page),
onAfterRender: (data, container) => console.log("Rendered", data),
});Filter
const dataDom = new NX.NexaDom({ /* … */ });
const filterSelect = document.getElementById("statusFilter");
filterSelect.addEventListener("change", async (e) => ""););Custom dataLoader
async function customDataLoader(
limit,
offset,
searchKeyword,
searchFields,
filterValue,
filterField,
sortBy,
sortOrder,
queryConfig
) {
const response = await fetch("/api/data", {
method: "POST",
body: JSON.stringify({ limit, offset, search: searchKeyword, sortBy, sortOrder }),
});
const data = await response.json();
return { totalCount: data.total, response: data.items };
}StorageData & StorageModelData
StorageData — default dataLoader jika memakai config. Memanggil
NX.Storage().models("Office").executeOperation(...) (hardcoded Office). Untuk model
lain: custom dataLoader atau opsi storage.
async function StorageData(
limit = 10,
offset = 0,
searchKeyword = "",
searchFields = [],
filterValue = "",
filterField = "",
sortBy = "id",
sortOrder = "DESC",
queryConfig = {}
)Returns: { totalCount, response }. Error: { totalCount: 0, response: [] }.
StorageModelData — dipakai otomatis saat storage.model diisi; signature sama;
internal menyimpan storageModelTable, storageModelSelect,
storageModelQueryHook.
Catatan penting (ringkas)
- Property
nopada setiap item — penomoran mengikuti sort ASC/DESC. - localStorage: halaman
NexaDom_page_{paginationSelector}; items per pagenexa_tabel_items_per_page_{containerSelector}. - Auto setup: debounce search 300ms, sort listener, load awal
loadRealDataAndUpdate(). - Global:
window.NX.currentState,window.NX.pageInfo. - Integrasi EkasticTabel: lebar kolom, inline data, filter cache.
- Akses instance:
container._NexaDomInstance. dataDom.responseselalu data terbaru setelah pagination/search/filter.
Error handling
Pesan error di area pagination, array kosong jika loader gagal, koreksi halaman melebihi total, try/catch pada operasi async.
Lifecycle
- Constructor — state + load awal non-blocking
loadRealDataAndUpdate()— data pertama + spinner jika aktifautoSetup()— search, sort, overridegoToPageinit()— init lengkap (blocking)loadData()→updateDataContainer()(tambahno) → render pagination
Best practices
configbukanqueryConfigdi constructororderbukanitemsPerPage- Pilih
renderatau template manual dariresponse onAfterRenderuntuk init komponen lain- Filter/search/sort lewat
update*, bukan ubah config mentah - Tabel SQL →
storage; skema Office/alias →config storage.queryhanya untuk kondisi tetap; variasi search lewat UI
Route & fragmen HTML: NX.html + hydrate
Muat fragmen HTML dari appRoot (mis. templates/), substitusi
{title}, {description}, lalu result.hydrate(container, lists)
untuk list NexaForge. Data dari tabel: await NX.NexaForgeView.hydrateStorage(container, { storage: { model, query? }, … })
— lihat NexaForge.md.
<section class="exam-sheet">
<h2>{title}</h2>
<p class="exam-lead">{description}</p>
<div id="daftar-user" NexaForge="user">
<div class="baris">
<span>{user.nama}</span><span>{user.email}</span>
</div>
</div>
</section>const result = await NX.html("exam", {
title: routeMeta.title || "Contact",
description: routeMeta.description || "",
});
if (!result.success || result.content == null) return;
container.innerHTML = result.content;
if (typeof result.hydrate === "function") {
result.hydrate(container, { user: users });
}Referensi NexaForge (Dom/NexaForge.js)
| Simbol | Arti |
|---|---|
NX.NexaForgeView |
Kelas NexaForge |
NX.html(...) |
Factory: fragmen statis + substitusi {kunci}; hasil bisa punya hydrate |
Metode statis: SENSITIVE_FIELDS, addSensitiveFields /
removeSensitiveFields, getNexaForgeAttr(el), hydrate(root, lists).
Constructor: elementById wajib; data per extractor; order,
search + searchableFields, pagination, filter,
endpoint (mode API), dll.
Event: nexadom:dataLoaded, nexadom:dataError; mode list:
dataReloaded, dataDeleted, dll. Detail di kode sumber
assets/modules/Dom/NexaForge.js.
License
Internal use only (sesuai NexaDom.md).