Skip to content

Commit 7098ad3

Browse files
committed
feat: changes in style, and pagination mechanism
Style of sorting arrow changed to absolute to avoid jumping to next row Improved code readability according to vue style guide
1 parent 62c82ef commit 7098ad3

File tree

1 file changed

+127
-98
lines changed

1 file changed

+127
-98
lines changed

src/components/Table/CTable.vue

Lines changed: 127 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,56 @@
11
<template>
22
<div>
33
<div v-if="optionsRow" class="row my-2 mx-0">
4-
<div v-show="optionsRow !== 'onlyPagination'" class="col-sm-6 form-inline p-0">
4+
5+
<div
6+
v-show="optionsRow !== 'onlyPagination'"
7+
class="col-sm-6 form-inline p-0"
8+
>
59
<label class="mr-2">Filter: </label>
6-
<input class="form-control c-table-filter"
7-
type="text"
8-
placeholder="type string..."
9-
@input="tableFilter = $event.target.value"
10-
:value="tableFilter"
10+
<input
11+
class="form-control c-table-filter"
12+
type="text"
13+
placeholder="type string..."
14+
@input="tableFilter = $event.target.value"
15+
:value="tableFilter"
1116
>
1217
</div>
18+
1319
<div v-show="optionsRow !== 'onlyFilter'" class="col-sm-6 p-0">
1420
<div :class="`form-inline ${optionsRow === 'onlyPagination' ? '' : 'float-sm-right'}`">
1521
<label class="mr-2">Items per page: </label>
16-
<input v-if="false"
17-
class="form-control"
18-
type="number"
19-
placeholder="type number..."
20-
@input="perPageItems = Number($event.target.value)"
21-
>
22-
<select v-if="true"
23-
class="form-control"
24-
@change="perPageItems = Number($event.target.value)"
22+
<select
23+
class="form-control"
24+
@change="perPageItems = Number($event.target.value)"
2525
>
26-
<option value="" selected disabled hidden>{{perPageItems}}</option>
27-
<option v-for="number in [5,10,20,50]" val="number">{{number}}</option>
26+
<option value="" selected disabled hidden>
27+
{{perPageItems}}
28+
</option>
29+
<option v-for="number in [5,10,20,50]" val="number">
30+
{{number}}
31+
</option>
2832
</select>
2933
</div>
3034
</div>
3135
</div>
36+
37+
3238
<slot name="overTable"/>
33-
<div :class="notResponsive ? '' : 'table-responsive'" class="position-relative">
39+
<div :class="`position-relative ${notResponsive ? '' : 'table-responsive'}`">
3440
<table :class="tableClasses">
3541
<thead :class="headVariant ? `thead-${headVariant}` : ''">
42+
3643
<tr>
37-
<th v-if="indexCol" style="width:40px"></th>
44+
<th v-if="indexColumn" style="width:40px"></th>
3845
<template v-for="(name, index) in columnNames">
3946
<th
4047
@click="changeSort(rawColumnNames[index], index)"
41-
:class="[headerClass(index), iconStyles]"
48+
:class="[headerClass(index), sortingIconStyles]"
4249
:style="headerStyles(index)"
4350
>
44-
<slot v-if="$slots[`${rawColumnNames[index]}-header`]"
45-
:name="`${rawColumnNames[index]}-header`"
46-
>
51+
<slot :name="`${rawColumnNames[index]}-header`">
52+
<div v-html="name" class="d-inline"></div>
4753
</slot>
48-
<div v-else v-html="name" class="d-inline"></div>
4954
<slot
5055
v-if="!noSorting && sortable(index)"
5156
name="sorting-icon"
@@ -56,63 +61,82 @@
5661
</th>
5762
</template>
5863
</tr>
64+
5965
<tr v-if="filterRow" class="table-sm">
60-
<th v-if="indexCol" class="pb-2">
61-
<i v-if="indexCol !== 'onlyIndexes'" class="cui-ban icons text-danger font-lg text-center d-block" @click="clear" title="clear table"></i>
66+
<th v-if="indexColumn" class="pb-2">
67+
<i
68+
v-if="indexColumn !== 'onlyIndexes'"
69+
class="cui-ban icons text-danger font-lg text-center d-block"
70+
@click="clear"
71+
title="clear table"
72+
></i>
6273
</th>
6374
<template v-for="(colName, index) in rawColumnNames" >
6475
<th :class="headerClass(index)">
65-
<slot :clear="clear, colName, index"
66-
:name="`${rawColumnNames[index]}-filter`"
76+
<slot
77+
:clear="clear, colName, index"
78+
:name="`${rawColumnNames[index]}-filter`"
6779
>
68-
<input v-if="!fields || !fields[index].noFilter"
69-
class="w-100 c-table-filter"
70-
@input="addColumnFilter(colName, $event.target.value)"
71-
:value="columnFilter[colName]"
80+
<input
81+
v-if="!fields || !fields[index].noFilter"
82+
class="w-100 c-table-filter"
83+
@input="addColumnFilter(colName, $event.target.value)"
84+
:value="columnFilter[colName]"
7285
></input>
7386
</slot>
7487
</th>
7588
</template>
7689
</tr>
7790
</thead>
91+
92+
7893
<tbody :style="bodyStyle" class="position-relative">
7994
<template v-for="(item, itemIndex) in currentItems" >
80-
<tr :class="item._classes" :tabindex="bodyStyle ? 0 : null"
81-
@click="rowClicked(item, itemIndex + firstItemIndex)">
82-
<slot v-if="indexCol"
83-
name="index-col"
84-
:index="firstItemIndex + itemIndex"
95+
<tr
96+
:class="item._classes" :tabindex="bodyStyle ? 0 : null"
97+
@click="rowClicked(item, itemIndex + firstItemIndex)"
98+
>
99+
<slot
100+
v-if="indexColumn"
101+
name="index-col"
102+
:index="firstItemIndex + itemIndex"
85103
>
86104
<td>
87-
{{indexCol !== 'onlyCleaner' ? firstItemIndex + itemIndex + 1 : ''}}
105+
{{indexColumn !== 'onlyCleaner' ? firstItemIndex + itemIndex + 1 : ''}}
88106
</td>
89107
</slot>
90108
<template v-for="(colName, index) in rawColumnNames" >
91-
<slot v-if="$scopedSlots[colName]"
92-
:name="colName"
93-
:item="item"
94-
:index="itemIndex + firstItemIndex"
109+
<slot
110+
v-if="$scopedSlots[colName]"
111+
:name="colName"
112+
:item="item"
113+
:index="itemIndex + firstItemIndex"
95114
/>
96-
<td v-else
97-
:class="cellClass(item, colName, index)"
98-
v-html="item[colName]"
115+
<td
116+
v-else
117+
:class="cellClass(item, colName, index)"
118+
v-html="item[colName]"
99119
></td>
100120
</template>
101121
</tr>
102-
<slot v-if="$scopedSlots.details || $scopedSlots.detailsRow"
103-
name="detailsRow"
104-
:item="item"
105-
:index="itemIndex + firstItemIndex"
106-
:colspan="colspan">
122+
<slot
123+
v-if="$scopedSlots.details || $scopedSlots.detailsRow"
124+
name="detailsRow"
125+
:item="item"
126+
:index="itemIndex + firstItemIndex"
127+
:colspan="colspan"
128+
>
107129
<tr class="p-0" style="border:none !important">
108-
<td :colspan="colspan"
109-
class="p-0"
110-
style="border:none !important"
130+
<td
131+
:colspan="colspan"
132+
class="p-0"
133+
style="border:none !important"
111134
>
112-
<slot name="details"
113-
:item="item"
114-
:index="itemIndex + firstItemIndex"
115-
:colspan="colspan"
135+
<slot
136+
name="details"
137+
:item="item"
138+
:index="itemIndex + firstItemIndex"
139+
:colspan="colspan"
116140
/>
117141
</td>
118142
</tr>
@@ -123,26 +147,31 @@
123147
<slot name="empty-table">
124148
<div class="text-center my-5">
125149
<h2>{{ passedItems.length ? 'No filtering results ' : 'No items'}}
126-
<i style="font-weight:1000" class="text-danger icons font-2xl cui-ban"></i>
150+
<i
151+
style="font-weight:1000"
152+
class="text-danger icons
153+
font-2xl cui-ban"
154+
></i>
127155
</h2>
128156
</div>
129157
</slot>
130158
</td>
131159
</tr>
132160
</tbody>
161+
162+
133163
<tfoot v-if="footer && currentItems.length > 3">
134164
<tr>
135-
<th v-if="indexCol" style="width:40px"></th>
165+
<th v-if="indexColumn" style="width:40px"></th>
136166
<template v-for="(name, index) in columnNames">
137-
<th @click="changeSort(rawColumnNames[index], index)"
138-
:class="[headerClass(index), iconStyles]"
139-
:style="headerStyles(index)"
167+
<th
168+
@click="changeSort(rawColumnNames[index], index)"
169+
:class="[headerClass(index), sortingIconStyles]"
170+
:style="headerStyles(index)"
140171
>
141-
<slot v-if="$slots[`${rawColumnNames[index]}-header`]"
142-
:name="`${rawColumnNames[index]}-header`"
143-
>
172+
<slot :name="`${rawColumnNames[index]}-header`">
173+
<div v-html="name" class="d-inline"></div>
144174
</slot>
145-
<div v-else v-html="name" class="d-inline"></div>
146175
<slot
147176
v-if="!noSorting && sortable(index)"
148177
name="sorting-icon"
@@ -156,17 +185,29 @@
156185
</tfoot>
157186
<slot name="caption"/>
158187
</table>
159-
<div v-if="loading" :style="topLoadingPosition" style="position:absolute;left:50%;transform:translateX(-50%);">
160-
<div class="spinner-border text-success" :style="spinnerSize" role="status">
188+
189+
190+
<div
191+
v-if="loading"
192+
:style="topLoadingPosition"
193+
style="position:absolute;left:50%;transform:translateX(-50%);"
194+
>
195+
<div
196+
class="spinner-border text-success"
197+
:style="spinnerSize"
198+
role="status"
199+
>
161200
<span class="sr-only">Loading...</span>
162201
</div>
163202
</div>
164203
</div>
165204
<slot name="underTable"/>
205+
206+
166207
<CPagination v-if="!noPagination"
167-
v-show="pages > 1"
208+
v-show="totalPages > 1"
168209
v-model="page"
169-
:pages="pages"
210+
:pages="totalPages"
170211
v-bind="paginationProps"
171212
/>
172213
</div>
@@ -188,7 +229,7 @@ export default {
188229
default: 10
189230
},
190231
activePage: Number,
191-
indexCol: [Boolean, String],
232+
indexColumn: [Boolean, String],
192233
filterRow: Boolean,
193234
noPagination: Boolean,
194235
paginationProps: Object,
@@ -224,7 +265,6 @@ export default {
224265
sorter: { name: this.defaultSorter.name, direction: this.defaultSorter.direction },
225266
firstItemIndex: 0,
226267
page: this.activePage || 1,
227-
pages: 0,
228268
perPageItems: this.perPage,
229269
passedItems: this.items
230270
}
@@ -263,12 +303,14 @@ export default {
263303
},
264304
currentItems () {
265305
if (this.computedPage) {
266-
this.checkPagination()
267306
this.firstItemIndex = (this.computedPage - 1) * this.perPageItems
268307
return this.sortedItems.slice(this.firstItemIndex, this.firstItemIndex + this.perPageItems)
269308
}
270309
return this.sortedItems
271310
},
311+
totalPages () {
312+
return Math.ceil((this.sortedItems.length)/ this.perPageItems) || 1
313+
},
272314
computedPage () {
273315
return this.noPagination ? this.activePage : this.page
274316
},
@@ -307,8 +349,11 @@ export default {
307349
bodyStyle () {
308350
return this.$listeners && this.$listeners['row-clicked'] ? 'cursor:pointer' : ''
309351
},
352+
sortingIconStyles () {
353+
return !this.noSorting ? 'position-relative pr-4' : ''
354+
},
310355
colspan () {
311-
return this.indexCol ? this.rawColumnNames.length + 1 : this.rawColumnNames.length
356+
return this.indexColumn ? this.rawColumnNames.length + 1 : this.rawColumnNames.length
312357
},
313358
topLoadingPosition () {
314359
const headerHeight = (this.filterRow ? 38 : 0) + ( this.small ? 32 + 4 : 46 + 7)
@@ -318,32 +363,22 @@ export default {
318363
const size = this.small ? '1.4rem' : this.currentItems.length === 1 ? '2rem' : '3rem'
319364
return `width:${size};height:${size}`
320365
},
321-
iconStyles () {
322-
return !this.noSorting ? 'position-relative pr-4' : ''
323-
}
324-
// loadingStyles () {
325-
// return !this.loading ? '' :
326-
// `opacity: .4; ${this.loading === 'noEvents' ? 'pointer-events:none' : ''}`
327-
// }
366+
328367
},
329368
watch: {
330-
// filter () { deep:true },
331369
items (val, oldVal) {
332370
if(val.length !== oldVal.length || JSON.stringify(val) !== JSON.stringify(oldVal))
333371
this.passedItems = val
372+
},
373+
totalPages: {
374+
immediate: true,
375+
handler (val, oldVal) {
376+
if(val !== oldVal)
377+
this.$emit('pages-change', val)
378+
}
334379
}
335380
},
336381
methods: {
337-
log (col) {
338-
console.log(col)
339-
},
340-
checkPagination () {
341-
const pages = Math.ceil((this.sortedItems.length)/ this.perPageItems) || 1
342-
if(pages !== this.pages){
343-
this.$emit('pages-change', pages)
344-
this.pages = pages
345-
}
346-
},
347382
changeSort (name, index) {
348383
if(index && !this.sortable(index))
349384
return
@@ -354,9 +389,6 @@ export default {
354389
this.sorter.direction = 0
355390
this.sorter.name = name
356391
},
357-
// setTableFilter (val) {
358-
// this.filter = val
359-
// },
360392
addColumnFilter (colName, value) {
361393
this.$set(this.columnFilter, colName, value)
362394
},
@@ -375,9 +407,6 @@ export default {
375407
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
376408
.join(' ')
377409
},
378-
// rowClass (item) {
379-
// return item._classes ? item._classes : ''
380-
// },
381410
cellClass (item, colName, index) {
382411
let classes = []
383412
if(item._cellClasses && item._cellClasses[colName])

0 commit comments

Comments
 (0)