<!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>