Nxdom Framework

Nusantara eXtreme Development Object Model — dokumentasi resmi

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
  • render opsional atau akses dataDom.response
  • Spinner NexaSpinner / NX.spinner (opsional)
  • Property no untuk nomor urut per baris
  • Sumber storageNX.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 &lt;…&gt; 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 listeners
  • loadData() — load dari dataLoader
  • goToPage(page) — navigasi halaman
  • updateSearch(keyword, fields), updateFilter(value, field), updateSort(by, order)
  • updateItemsPerPage(n), refresh(showLoading?)
  • getState(), getData(), savePageState(page)
  • destroy() — bersihkan listener + spinner internal
  • showSpinner() / 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 no pada setiap item — penomoran mengikuti sort ASC/DESC.
  • localStorage: halaman NexaDom_page_{paginationSelector}; items per page nexa_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.response selalu 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

  1. Constructor — state + load awal non-blocking
  2. loadRealDataAndUpdate() — data pertama + spinner jika aktif
  3. autoSetup() — search, sort, override goToPage
  4. init() — init lengkap (blocking)
  5. loadData()updateDataContainer() (tambah no) → render pagination

Best practices

  1. config bukan queryConfig di constructor
  2. order bukan itemsPerPage
  3. Pilih render atau template manual dari response
  4. onAfterRender untuk init komponen lain
  5. Filter/search/sort lewat update*, bukan ubah config mentah
  6. Tabel SQL → storage; skema Office/alias → config
  7. storage.query hanya 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).