166 lines
5.3 KiB
JavaScript
166 lines
5.3 KiB
JavaScript
|
class MiniDT {
|
||
|
constructor(config) {
|
||
|
if (!config.url || !config.target || !config.cols) return false;
|
||
|
|
||
|
this.rows = []
|
||
|
this.page = 0
|
||
|
this.total = 0
|
||
|
this.total_pages = 0
|
||
|
this.limit = (!!config.limit) ? config.limit : 20
|
||
|
this.params = (!!config.params) ? config.params : {}
|
||
|
this.url = config.url
|
||
|
this.cols = {}
|
||
|
this.target = document.getElementById(config.target)
|
||
|
if (!this.target.classList.contains('mini-dt')) this.target.classList.add('mini-dt')
|
||
|
|
||
|
// Create table header, body and footer
|
||
|
this.thead = this.target.createTHead()
|
||
|
this.tbody = this.target.createTBody()
|
||
|
this.tfoot = this.target.createTFoot()
|
||
|
this.tfoot.classList.add('hide')
|
||
|
|
||
|
// Draw header columns
|
||
|
const head_row = this.thead.insertRow()
|
||
|
|
||
|
config.cols.forEach( col => {
|
||
|
const th = document.createElement('th')
|
||
|
th.innerText = col.title
|
||
|
|
||
|
if (!!col.align && ['center', 'right'].includes(col.align)) th.classList.add(`text-${col.align}`)
|
||
|
|
||
|
// Las columnas las almacenamos de este modo para ahorrar tener que recorrer el array cada vez
|
||
|
this.cols[col.col] = {
|
||
|
title: col.title,
|
||
|
render: (!!col.render && typeof col.render === 'function') ? col.render : null,
|
||
|
align: (!!col.align && ['center', 'right'].includes(col.align)) ? col.align: null
|
||
|
}
|
||
|
|
||
|
// Añadimos la columna a la cabecera
|
||
|
head_row.appendChild(th)
|
||
|
});
|
||
|
|
||
|
// Y añadimos la fila a la cabecera
|
||
|
this.thead.appendChild(head_row)
|
||
|
|
||
|
// Draw footer
|
||
|
const row_footer = this.tfoot.insertRow()
|
||
|
const th = document.createElement('th')
|
||
|
th.setAttribute('colspan', Object.keys(this.cols).length)
|
||
|
|
||
|
// Pagination container
|
||
|
this.pagination_container = document.createElement('div')
|
||
|
this.pagination_container.classList.add('pagination')
|
||
|
|
||
|
// Pagination text
|
||
|
this.pageText = document.createTextNode(`Page 1 of 1`)
|
||
|
this.pagination_container.appendChild(this.pageText)
|
||
|
|
||
|
// Previous page button
|
||
|
this.prev_btn = document.createElement('button')
|
||
|
//this.prev_btn.innerText = '<'
|
||
|
this.prev_btn.classList.add('prev-btn')
|
||
|
this.prev_btn.addEventListener('click', this.previous)
|
||
|
this.pagination_container.appendChild(this.prev_btn)
|
||
|
|
||
|
// Page selector
|
||
|
this.pageSelector = document.createElement('select')
|
||
|
this.pageSelector.classList.add('page-selector')
|
||
|
this.pageSelector.addEventListener('change', this.changePage)
|
||
|
this.pagination_container.appendChild(this.pageSelector)
|
||
|
|
||
|
// Next page button
|
||
|
this.next_btn = document.createElement('button')
|
||
|
//this.next_btn.innerText = '>'
|
||
|
this.next_btn.classList.add('next-btn')
|
||
|
this.next_btn.addEventListener('click', this.next)
|
||
|
this.pagination_container.appendChild(this.next_btn)
|
||
|
|
||
|
th.appendChild(this.pagination_container)
|
||
|
row_footer.appendChild(th);
|
||
|
|
||
|
this.getData()
|
||
|
}
|
||
|
|
||
|
getData = async () => {
|
||
|
this.rows = []
|
||
|
this.params.limit = this.limit
|
||
|
this.params.page = this.page
|
||
|
|
||
|
try {
|
||
|
const resp = await fetch(this.url + '?' + new URLSearchParams(this.params).toString())
|
||
|
const data = await resp.json()
|
||
|
if (!!data.data) this.rows = data.data
|
||
|
this.total = (!!data.total) ? data.total : 0
|
||
|
|
||
|
if (this.total > 0 && this.total > this.limit) this.total_pages = Math.ceil(this.total / this.limit)
|
||
|
else this.total_pages = 1
|
||
|
|
||
|
this.pageText.textContent = `Page ${this.page + 1} of ${this.total_pages}`
|
||
|
} catch (err) {
|
||
|
console.error(err);
|
||
|
}
|
||
|
|
||
|
this.render()
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Rendering the component
|
||
|
*/
|
||
|
render = () => {
|
||
|
this.tbody.innerHTML = ''
|
||
|
|
||
|
if (this.rows.length == 0) {
|
||
|
const row = this.tbody.insertRow()
|
||
|
const td = document.createElement('td')
|
||
|
td.setAttribute('colspan', Object.keys(this.cols).length)
|
||
|
td.innerHTML = '<strong>No data</strong>'
|
||
|
row.appendChild(td)
|
||
|
this.tfoot.classList.add('hide')
|
||
|
} else {
|
||
|
this.rows.forEach( row => {
|
||
|
const tr = this.tbody.insertRow()
|
||
|
|
||
|
Object.keys(this.cols).forEach( key => {
|
||
|
if (key in row) {
|
||
|
const cell = tr.insertCell()
|
||
|
cell.setAttribute('data-title', this.cols[key].title)
|
||
|
if (!!this.cols[key].align) cell.classList.add(`text-${this.cols[key].align}`)
|
||
|
|
||
|
cell.innerHTML = (!!this.cols[key].render)
|
||
|
? this.cols[key].render(row)
|
||
|
: cell.innerText = row[key]
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
this.tfoot.classList.remove('hide')
|
||
|
}
|
||
|
|
||
|
this.pageSelector.removeEventListener('change', this.changePage)
|
||
|
this.pageSelector.innerHTML = ''
|
||
|
|
||
|
for (let i=0; i < this.total_pages; i++) {
|
||
|
this.pageSelector.append(new Option(i + 1, i, i == this.page))
|
||
|
}
|
||
|
|
||
|
this.pageSelector.value = this.page
|
||
|
this.pageSelector.addEventListener('change', this.changePage)
|
||
|
}
|
||
|
|
||
|
changePage = (value) => {
|
||
|
this.page = (value instanceof Event) ? parseInt(value.target.value) : parseInt(value)
|
||
|
this.pageText.textContent = `Page ${this.page + 1} of ${this.total_pages}`
|
||
|
this.getData()
|
||
|
}
|
||
|
|
||
|
previous = () => {
|
||
|
if (this.page > 0) this.page--
|
||
|
this.pageText.textContent = `Page ${this.page + 1} of ${this.total_pages}`
|
||
|
this.getData()
|
||
|
}
|
||
|
|
||
|
next = () => {
|
||
|
if (this.page < this.total_pages - 1) this.page++
|
||
|
this.pageText.textContent = `Page ${this.page + 1} of ${this.total_pages}`
|
||
|
this.getData()
|
||
|
}
|
||
|
}
|