You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tech-interview-handbook/experimental/domain/pagination-sorting/index.html

145 lines
4.7 KiB

<!doctype html>
<head>
<style>
body {
font-family: 'Helvetica', sans-serif;
}
</style>
</head>
<body>
<h1>People</h1>
<table class="js-table">
<tr class="js-table-header">
<th data-field="name">Name</th>
<th data-field="age">Age</th>
<th data-field="email">Email</th>
</tr>
<tbody class="js-table-body">
</tbody>
</table>
<button class="js-page-button button-prev" data-type="prev">Prev</button>
Page <span class="js-current-page"></span> / <span class="js-total-page"></span>
<button class="js-page-button button-next" data-type="next">Next</button>
<script type="text/javascript" src="data.js"></script>
<script>
(() => {
function init() {
const DOM = {
$pageButtons: document.querySelectorAll('.js-page-button'),
$prevButton: document.querySelector('.js-page-button.button-prev'),
$nextButton: document.querySelector('.js-page-button.button-next'),
$tableHeader: document.querySelector('.js-table-header'),
$tableBody: document.querySelector('.js-table-body'),
$currentPage: document.querySelector('.js-current-page'),
$totalPages: document.querySelector('.js-total-page'),
};
const PAGE_SIZE = 10;
function initialState() {
return {
currentPage: 0,
totalPages: 0,
sortField: 'name',
sortOrder: 'asc',
data,
};
}
let state = initialState();
state.totalPages = Math.ceil(state.data.length / PAGE_SIZE);
function navigatePages(type) {
let newCurrentPage = state.currentPage + (type === 'prev' ? -1 : 1);
newCurrentPage = Math.max(0, newCurrentPage);
newCurrentPage = Math.min(newCurrentPage, state.totalPages - 1);
state.currentPage = newCurrentPage;
}
function setSortField(field) {
state.currentPage = 0;
if (state.sortField !== field) {
state.sortField = field;
state.sortOrder = 'asc';
} else {
state.sortOrder = state.sortOrder === 'asc' ? 'desc' : 'asc';
}
}
function attachEventListeners() {
// Pagination.
DOM.$pageButtons.forEach(el => {
el.addEventListener('click', function () {
navigatePages(this.getAttribute('data-type'));
render();
});
});
// Sorting.
DOM.$tableHeader.addEventListener('click', function (event) {
const el = event.target;
const field = el.getAttribute('data-field');
if (el.tagName !== 'TH' || !field) {
return;
}
setSortField(field);
render();
});
}
function render() {
DOM.$tableBody.innerHTML = '';
// Sort data.
const sortField = state.sortField;
state.data.sort((a, b) => {
switch (sortField) {
case 'name':
case 'email':
return a[sortField] > b[sortField] ? 1 : -1;
case 'age':
return a[sortField] - b[sortField];
}
});
if (state.sortOrder === 'desc') {
state.data.reverse();
}
// Create table rows.
const pageData = state.data.slice(state.currentPage * PAGE_SIZE, state.currentPage * PAGE_SIZE + PAGE_SIZE);
const $tableRowsFragment = document.createDocumentFragment();
pageData.forEach(person => {
const $tableRow = document.createElement('tr');
['name', 'age', 'email'].forEach(field => {
const $tableCell = document.createElement('td');
$tableCell.textContent = person[field];
$tableRow.appendChild($tableCell);
});
$tableRowsFragment.appendChild($tableRow);
});
DOM.$tableBody.appendChild($tableRowsFragment);
// Pagination buttons disabled states.
DOM.$currentPage.textContent = state.currentPage + 1;
DOM.$totalPages.textContent = state.totalPages;
if (state.currentPage === 0) {
DOM.$prevButton.setAttribute('disabled', true);
} else {
DOM.$prevButton.removeAttribute('disabled');
}
if (state.currentPage === state.totalPages - 1) {
DOM.$nextButton.setAttribute('disabled', true);
} else {
DOM.$nextButton.removeAttribute('disabled');
}
}
render();
attachEventListeners();
}
document.addEventListener('DOMContentLoaded', init);
})();
</script>
</body>
</html>