Task Pagination (#38)
continuous-integration/drone/push Build is passing Details

This commit is contained in:
konrad 2019-12-03 18:09:12 +00:00
parent 99cc06edee
commit 2302a46d9b
4 changed files with 93 additions and 7 deletions

View File

@ -58,7 +58,7 @@
},
watch: {
// call again the method if the route changes
'$route': 'loadList'
'$route.path': 'loadList'
},
methods: {
loadList() {

View File

@ -1,5 +1,5 @@
<template>
<div class="loader-container" :class="{ 'is-loading': listService.loading}">
<div class="loader-container" :class="{ 'is-loading': listService.loading || taskCollectionService.loading}">
<form @submit.prevent="addTask()">
<div class="field is-grouped">
<p class="control has-icons-left is-expanded" :class="{ 'is-loading': taskService.loading}">
@ -21,8 +21,8 @@
<div class="columns">
<div class="column">
<div class="tasks" v-if="this.list.tasks && this.list.tasks.length > 0" :class="{'short': isTaskEdit}">
<div class="task" v-for="l in list.tasks" :key="l.id">
<div class="tasks" v-if="tasks && tasks.length > 0" :class="{'short': isTaskEdit}">
<div class="task" v-for="l in tasks" :key="l.id">
<span>
<div class="fancycheckbox">
<input @change="markAsDone" type="checkbox" :id="l.id" :checked="l.done" style="display: none;">
@ -69,6 +69,19 @@
</div>
</div>
</div>
<nav class="pagination is-centered" role="navigation" aria-label="pagination" v-if="taskCollectionService.totalPages > 1">
<button class="pagination-previous" @click="loadTasks(currentPage - 1)" :disabled="currentPage === 1">Previous</button>
<button class="pagination-next" @click="loadTasks(currentPage + 1)" :disabled="currentPage === taskCollectionService.totalPages">Next page</button>
<ul class="pagination-list">
<template v-for="(p, i) in pages">
<li :key="'page'+i" v-if="p.isEllipsis"><span class="pagination-ellipsis">&hellip;</span></li>
<li :key="'page'+i" v-else>
<router-link :to="{name: 'showList', query: { page: p.number }}" :class="{'is-current': p.number === currentPage}" class="pagination-link" :aria-label="'Goto page ' + p.number">{{ p.number }}</router-link>
</li>
</template>
</ul>
</nav>
</div>
</template>
@ -81,6 +94,7 @@
import EditTask from './edit-task'
import TaskModel from '../../models/task'
import PriorityLabel from './reusable/priorityLabel'
import TaskCollectionService from '../../services/taskCollection'
export default {
data() {
@ -88,7 +102,11 @@
listID: this.$route.params.id,
listService: ListService,
taskService: TaskService,
taskCollectionService: TaskCollectionService,
pages: [],
currentPage: 0,
list: {},
tasks: [],
isTaskEdit: false,
taskEditTask: TaskModel,
newTaskText: '',
@ -107,11 +125,14 @@
watch: {
theList() {
this.list = this.theList
}
this.loadTasks(1)
},
'$route.query': 'loadTasksForPage', // Only listen for query path changes
},
created() {
this.listService = new ListService()
this.taskService = new TaskService()
this.taskCollectionService = new TaskCollectionService()
this.taskEditTask = null
this.isTaskEdit = false
},
@ -128,6 +149,48 @@
message.error(e, this)
})
},
loadTasks(page) {
this.taskCollectionService.getAll({listID: this.$route.params.id}, {}, page)
.then(r => {
this.$set(this, 'tasks', r)
this.$set(this, 'pages', [])
this.currentPage = page
for (let i = 0; i < this.taskCollectionService.totalPages; i++) {
// Show ellipsis instead of all pages
if(
i > 0 && // Always at least the first page
(i + 1) < this.taskCollectionService.totalPages && // And the last page
(
// And the current with current + 1 and current - 1
(i + 1) > this.currentPage + 1 ||
(i + 1) < this.currentPage - 1
)
) {
// Only add an ellipsis if the last page isn't already one
if(this.pages[i - 1] && !this.pages[i - 1].isEllipsis) {
this.pages.push({
number: 0,
isEllipsis: true,
})
}
continue
}
this.pages.push({
number: i + 1,
isEllipsis: false,
})
}
})
.catch(e => {
message.error(e, this)
})
},
loadTasksForPage(e) {
this.loadTasks(e.page)
},
markAsDone(e) {
let updateFunc = () => {
// We get the task, update the 'done' property and then push it to the api.

View File

@ -18,6 +18,9 @@ export default class AbstractService {
update: '',
delete: '',
}
// This contains the total number of pages and the number of results for the current page
totalPages = 0
resultCount = 0
/////////////
// Service init
@ -96,7 +99,7 @@ export default class AbstractService {
useDeleteInterceptor() {
return true
}
/////////////////////
// Global error handler
///////////////////
@ -298,13 +301,16 @@ export default class AbstractService {
* The difference between this and get() is this one is used to get a bunch of data (an array), not just a single object.
* @param model The model to use. The request path is built using the values from the model.
* @param params Optional query parameters
* @param page The page to get
* @returns {Q.Promise<any>}
*/
getAll(model = {}, params = {}) {
getAll(model = {}, params = {}, page = 1) {
if (this.paths.getAll === '') {
return Promise.reject({message: 'This model is not able to get data.'})
}
params.page = page
const cancel = this.setLoading()
model = this.beforeGet(model)
return this.http.get(this.getReplacedRoute(this.paths.getAll, model), {params: params})
@ -312,6 +318,9 @@ export default class AbstractService {
return this.errorHandler(error)
})
.then(response => {
this.resultCount = Number(response.headers['x-pagination-result-count'])
this.totalPages = Number(response.headers['x-pagination-total-pages'])
if (Array.isArray(response.data)) {
return Promise.resolve(response.data.map(entry => {
return this.modelGetAllFactory(entry)

View File

@ -0,0 +1,14 @@
import AbstractService from './abstractService'
import TaskModel from '../models/task'
export default class TaskCollectionService extends AbstractService {
constructor() {
super({
getAll: '/lists/{listID}/tasks',
})
}
modelFactory(data) {
return new TaskModel(data)
}
}