From 1b7428c37b2c3d9f4f31969ba049b1016445a48a Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Sun, 22 Dec 2019 19:00:56 +0300 Subject: [PATCH] pagination component --- config/routes/api.js | 11 ++ config/routes/control-panel.js | 5 +- dist/public/css/style.css | 3 + dist/views/admin/items.pug | 16 +-- src/admin/components/categories.component.js | 37 +++---- src/admin/components/items.component.js | 28 ++++-- src/admin/components/pagination.component.js | 100 +++++++++++++++++++ src/admin/core/component.js | 6 +- src/admin/index.js | 2 + src/admin/services/api.service.js | 9 ++ 10 files changed, 176 insertions(+), 41 deletions(-) create mode 100644 src/admin/components/pagination.component.js diff --git a/config/routes/api.js b/config/routes/api.js index fe11d31..bd3b4b2 100644 --- a/config/routes/api.js +++ b/config/routes/api.js @@ -25,6 +25,17 @@ module.exports = function(server, db) { } } else res.send({error: 'Товаров в магазине пока что нет.'}); }); + + server.get('/api/items/page/:page', async (req, res) => { + try { + const page = parseInt(req.params.page), + limit = parseInt(req.query.limit), + items = await db.collection('items').find({}, {skip: limit * (page - 1), limit}).toArray(); + items.length > 0 && !isNaN(page) ? res.json(items) : res.json({error: 'Такой страницы не существует.'}); + } catch (error) { + res.render('main/404'); + } + }); server.get('/api/items/:category', async (req, res) => { const items = await db.collection('items').find({category: req.params.category}).toArray(), diff --git a/config/routes/control-panel.js b/config/routes/control-panel.js index 3f56c8a..3b81e47 100644 --- a/config/routes/control-panel.js +++ b/config/routes/control-panel.js @@ -20,14 +20,17 @@ module.exports = function(server, db) { res.render('main/404'); } }); - server.get('/control-panel/items', checkAuthenticated, (req, res) => { + server.get('/control-panel/items', checkAuthenticated, async (req, res) => { try { + const items = await db.collection('items').find({}).toArray(); + const count = items.length; res.render('admin/items', { name: req.user.name, email: req.user.email, title: 'Digital-Store | Товары', host: req.headers.host, pageName: ['Товары', 'items'], + count: count / 2 }); } catch (error) { res.render('main/404'); diff --git a/dist/public/css/style.css b/dist/public/css/style.css index a46aa95..083a5b0 100644 --- a/dist/public/css/style.css +++ b/dist/public/css/style.css @@ -707,6 +707,9 @@ footer.main-footer { max-height: 385px; overflow-y: hidden; } +#items .card-content { + min-height: 519px; +} footer.admin-footer{ background-color: #fff; border-top: 1px solid #e0e0e0; diff --git a/dist/views/admin/items.pug b/dist/views/admin/items.pug index 4f199dc..4fbd80d 100644 --- a/dist/views/admin/items.pug +++ b/dist/views/admin/items.pug @@ -33,20 +33,8 @@ body.has-fixed-sidenav tbody #loader.progress .indeterminate - .divider - ul.pagination.center - li.active - a(href="#" class="disabled") - i.material-icons chevron_left - li - a(href="#" class="active") 1 - li - a(href="#") 2 - li - a(href="#") 3 - li - a(href="#" class="disabled") - i.material-icons chevron_right + ul#pagination.pagination.center(data-page="1") + include ./assets/templates/footer.pug include ./assets/scripts.pug \ No newline at end of file diff --git a/src/admin/components/categories.component.js b/src/admin/components/categories.component.js index a20016a..29092f4 100644 --- a/src/admin/components/categories.component.js +++ b/src/admin/components/categories.component.js @@ -9,16 +9,16 @@ export class CategoriesComponent extends Component { } setElems() { - // обозначим все селекты для рендера в них наши категории и киноки в дальнейшем + // обозначим все селекты для рендера в них наши категории и иконки в дальнейшем this.$editSelect = this.$el.querySelector('#edit select'); this.$dellSelect = this.$el.querySelector('#delete select'); this.$iconsSelect = this.$el.querySelector('#icons select'); this.$dellIconsSelect = this.$el.querySelector('#dellIcon select'); // формы - this.$dellIconFrom = this.$el.querySelector('#dellIcon'); - this.$addForm = this.$el.querySelector('#addCategory'); - this.$dellForm = this.$el.querySelector('#dellCategory'); + this.$dellIconFrom = this.$el.querySelector('#dellIcon'); // удаление иконки + this.$addForm = this.$el.querySelector('#addCategory'); // добавление категории + this.$dellForm = this.$el.querySelector('#dellCategory'); // удаление категории // добавим ивенты на наши формы this.$dellIconFrom.addEventListener('submit', this.dellIcon.bind(this)); @@ -27,10 +27,10 @@ export class CategoriesComponent extends Component { } async init() { - const categories = await apiService.getCategories(); - const icons = await apiService.getIcons(); - const icons_html = renderIcons(icons); - const categories_html = renderCategories(categories); + const categories = await apiService.getCategories(), + icons = await apiService.getIcons(), + icons_html = renderIcons(icons), + categories_html = renderCategories(categories); this.$editSelect.insertAdjacentHTML('beforeend', categories_html); this.$dellSelect.insertAdjacentHTML('beforeend', categories_html); @@ -41,25 +41,28 @@ export class CategoriesComponent extends Component { async addCategory(e) { e.preventDefault(); - const categories = await apiService.getCategories(); - const title = this.$addForm.elements[0].value.toLowerCase().trim(); - const index = categories.map((category) => {return category.title}).indexOf(title); + const categories = await apiService.getCategories(), + title = this.$addForm.elements[0].value.toLowerCase().trim(), + index = categories.map((category) => {return category.title}).indexOf(title); + index != -1 ? alert('Такая категория уже существует, придумайте другое название.') : this.$addForm.submit(); } async deleteCategory(e) { e.preventDefault(); - const categories = await apiService.getCategories(); - const title = this.$dellForm.elements[0].value.toLowerCase().trim(); - const index = categories.map((category) => {return category.title}).indexOf(title); + const categories = await apiService.getCategories(), + title = this.$dellForm.elements[0].value.toLowerCase().trim(), + index = categories.map((category) => {return category.title}).indexOf(title); + index != -1 ? this.$dellForm.submit() : alert('Выберите категорию для удаления.'); } async dellIcon(e) { e.preventDefault(); - const icons = await apiService.getIcons(); - const currIcon = e.target.elements[0].value; - const index = icons.indexOf(currIcon); + const icons = await apiService.getIcons(), + currIcon = e.target.elements[0].value, + index = icons.indexOf(currIcon); + index != -1 ? e.target.submit() : alert('Выберите иконку для удаления.'); } } \ No newline at end of file diff --git a/src/admin/components/items.component.js b/src/admin/components/items.component.js index 09d8805..348d037 100644 --- a/src/admin/components/items.component.js +++ b/src/admin/components/items.component.js @@ -8,16 +8,30 @@ export class ItemsComponent extends Component { this.loader = loader; } - setElems() { + async init() { + const items = await apiService.getItemsOffset(1, 5), + categories = await apiService.getCategories(), + html = renderItems(items, categories); + this.$table = this.$el.querySelector('table tbody'); + this.$table.insertAdjacentHTML('afterbegin', html); + this.onHide(); } - async init() { - const categories = await apiService.getCategories(); - const items = await apiService.getItems(); - const html = renderItems(items, categories); - - this.$table.insertAdjacentHTML('afterbegin', html); + onHide() { this.loader.hide(); } + + onShow() { + this.loader.show(); + this.$table.innerHTML = ''; + } + + async insertItems(page, limit) { + const items = await apiService.getItemsOffset(page, limit), + categories = await apiService.getCategories(), + html = renderItems(items, categories); + + this.$table.insertAdjacentHTML('afterbegin', html); + } } \ No newline at end of file diff --git a/src/admin/components/pagination.component.js b/src/admin/components/pagination.component.js new file mode 100644 index 0000000..9cfda23 --- /dev/null +++ b/src/admin/components/pagination.component.js @@ -0,0 +1,100 @@ +import { Component } from "../core/component"; +import { apiService } from "../services/api.service"; + +export class PaginationComponent extends Component { + constructor(id, {items}) { + super(id); + this.limit = 5; + this.items = items; + } + + async init() { + await this.insertPages(); + this.$pages = this.$el.querySelectorAll('li'); + this.$el.addEventListener('click', this.buttonHandler.bind(this)); + this.$el.querySelector('li').nextElementSibling.classList.add('active'); + } + + buttonHandler(e) { + e.preventDefault(); + if (e.target.dataset.move) { + const value = parseInt(e.target.dataset.move), + target = e.target.parentNode; + + this.removeActive(); + target.classList.add('active'); + this.moveTo(value); + } else if (e.target.tagName.toLowerCase() === 'i') { + const moveType = e.target.parentNode.dataset.type, + value = parseInt(this.$el.dataset.page); + + moveType === 'prev' ? this.movePrev(value, this.$pages) : this.moveNext(value, this.$pages); + } + } + + updatePage(value) { + this.$el.setAttribute('data-page', value); + } + + removeActive() { + this.$pages.forEach(li => li.classList.remove('active')); + } + + setActive(li, value) { + li.forEach(li => {const page = parseInt(li.querySelector('a').dataset.move);page === value ? li.classList.add('active') : false;}); + } + + movePrev(value, li) { + if (value === 1) { + return 0; + } else { + --value; + this.removeActive(); + this.setActive(li, value); + this.updatePage(value); + this.items.onShow(); + this.items.insertItems(value, this.limit); + this.items.onHide(); + } + } + + moveTo(value) { + this.updatePage(value); + this.items.onShow(); + this.items.insertItems(value, this.limit); + this.items.onHide(); + } + + moveNext(value, li) { + const length = this.$pages.length - 2; + if (value === length) { + return 0; + } else { + ++value; + this.removeActive(); + this.setActive(li, value); + this.updatePage(value); + this.items.onShow(); + this.items.insertItems(value, this.limit); + this.items.onHide(); + } + } + + async insertPages() { + const pages = await apiService.getItems(), + count = pages.length / this.limit; + let html = ''; + + // назад + html += '
  • chevron_left
  • '; + + // все страницы + for (let i = 1; i <= count; i++) { + html += `
  • ${i}
  • `; + } + + // вперед + html += '
  • chevron_right
  • '; + this.$el.insertAdjacentHTML('afterbegin', html); + } +} \ No newline at end of file diff --git a/src/admin/core/component.js b/src/admin/core/component.js index aed6951..61f8068 100644 --- a/src/admin/core/component.js +++ b/src/admin/core/component.js @@ -14,10 +14,12 @@ export class Component { onHide() {} hide() { - this.$el ? this.$el.classList.add('hide') : false + this.$el ? this.$el.classList.add('hide') : false; + this.onHide(); } show() { - this.$el ? this.$el.classList.remove('hide') : false + this.$el ? this.$el.classList.remove('hide') : false; + this.onShow(); } } \ No newline at end of file diff --git a/src/admin/index.js b/src/admin/index.js index 4dba58c..a0d4efd 100644 --- a/src/admin/index.js +++ b/src/admin/index.js @@ -3,10 +3,12 @@ import { CategoriesComponent } from "./components/categories.component.js"; import { editCategoryModal } from "./modals/editCategory.modal.js"; import { ItemsComponent } from "./components/items.component.js"; import { LoaderComponent } from "./components/loader.component.js"; +import { PaginationComponent } from "./components/pagination.component.js"; const loader = new LoaderComponent('loader'); const categories = new CategoriesComponent('categories'); const items = new ItemsComponent('items', {loader}); +const pagination = new PaginationComponent('pagination', {items}); const editCategory = new editCategoryModal('editCategory', 'edit', 'editCategoryClose'); const materialize = new MaterializeConfig(); console.log('Control-Panel v1.0.0'); \ No newline at end of file diff --git a/src/admin/services/api.service.js b/src/admin/services/api.service.js index aa7e067..12b19c7 100644 --- a/src/admin/services/api.service.js +++ b/src/admin/services/api.service.js @@ -38,6 +38,15 @@ class ApiService { } } + async getItemsOffset(page, limit) { + try { + const request = `${this.url}/api/items/page/${page}?limit=${limit}`; + return useRequest(request); + } catch (err) { + console.error(err); + } + } + async getItemsOne(category, sorting) { try { if (sorting) {