16
16
</div >
17
17
18
18
<div
19
- v-if =" havePaginationMenu() "
19
+ v-if =" optionsRow !== 'noPagination' "
20
20
class =" c-col-sm-6 c-p-0"
21
21
:class =" optionsRow === 'noFilter' ? 'c-offset-sm-6' : ''"
22
22
>
29
29
<option value =" " selected disabled hidden >
30
30
{{perPageItems}}
31
31
</option >
32
- <option v-for =" number in [5,10,20,50]" val =" number" >
32
+ <option
33
+ v-for =" (number, key) in [5,10,20,50]"
34
+ :val =" number"
35
+ :key =" key"
36
+ >
33
37
{{number}}
34
38
</option >
35
39
</select >
49
53
@click =" changeSort(rawColumnNames[index], index)"
50
54
:class =" [headerClass(index), sortingIconStyles]"
51
55
:style =" headerStyles(index)"
56
+ :key =" index"
52
57
>
53
58
<slot :name =" `${rawColumnNames[index]}-header`" >
54
59
<div class =" c-d-inline" >{{name}}</div >
80
85
/>
81
86
</th >
82
87
<template v-for =" (colName , index ) in rawColumnNames " >
83
- <th :class =" headerClass(index)" >
88
+ <th :class =" headerClass(index)" :key = " index " >
84
89
<slot :name =" `${rawColumnNames[index]}-filter`" >
85
90
<input
86
91
v-if =" !fields || !fields[index].noFilter"
87
92
class =" c-w-100 c-table-filter"
88
93
@input =" addColumnFilter(colName, $event.target.value)"
89
94
:value =" columnFilter[colName]"
90
- ></ input >
95
+ / >
91
96
</slot >
92
97
</th >
93
98
</template >
100
105
<tr
101
106
:class =" item._classes" :tabindex =" bodyStyle ? 0 : null"
102
107
@click =" rowClicked(item, itemIndex + firstItemIndex)"
108
+ :key =" itemIndex"
103
109
>
104
110
<slot
105
111
v-if =" indexColumn"
119
125
:item =" item"
120
126
:index =" itemIndex + firstItemIndex"
121
127
/>
122
- <td v-else :class =" cellClass(item, colName, index)" >
128
+ <td
129
+ v-else
130
+ :class =" cellClass(item, colName, index)"
131
+ :key =" index"
132
+ >
123
133
{{item[colName]}}
124
134
</td >
125
135
</template >
128
138
v-if =" $scopedSlots.details"
129
139
class =" c-p-0"
130
140
style =" border :none !important "
141
+ :key =" 'details' + itemIndex"
131
142
>
132
143
<td
133
144
:colspan =" colspan"
168
179
@click =" changeSort(rawColumnNames[index], index)"
169
180
:class =" [headerClass(index), sortingIconStyles]"
170
181
:style =" headerStyles(index)"
182
+ :key =" index"
171
183
>
172
184
<slot :name =" `${rawColumnNames[index]}-header`" >
173
185
<div class =" c-d-inline" >{{name}}</div >
@@ -269,25 +281,34 @@ export default {
269
281
column: this .defaultSorter .column || null ,
270
282
asc: this .defaultSorter .asc || true
271
283
},
272
- firstItemIndex: 0 ,
273
284
page: this .activePage || 1 ,
274
285
perPageItems: this .perPage ,
275
286
passedItems: this .items || []
276
287
}
277
288
},
278
289
computed: {
279
290
columnFiltered () {
280
- let items = this .passedItems
291
+ let items = this .passedItems . slice ()
281
292
Object .keys (this .columnFilter ).forEach (key => {
282
- items = items .filter (item => String (item[key]).toLowerCase ().includes (this .columnFilter [key].toLowerCase ()))
293
+ items = items .filter (item => {
294
+ const columnFilter = this .columnFilter [key].toLowerCase ()
295
+ return String (item[key]).toLowerCase ().includes (columnFilter)
296
+ })
283
297
})
284
298
return items
285
299
},
300
+ filterableCols () {
301
+ return this .rawColumnNames .filter (name => {
302
+ return this .generatedColumnNames .includes (name)
303
+ })
304
+ },
286
305
tableFiltered () {
287
- let items = this .columnFiltered
306
+ let items = this .columnFiltered . slice ()
288
307
if (this .tableFilter ) {
308
+ const filter = this .tableFilter .toLowerCase ()
309
+ const hasFilter = (item ) => String (item).toLowerCase ().includes (filter)
289
310
items = items .filter (item => {
290
- return Object . keys (item) .filter (key => String (item[key]). toLowerCase (). includes ( this . tableFilter . toLowerCase () )).length
311
+ return this . filterableCols .filter (key => hasFilter (item[key])).length
291
312
})
292
313
}
293
314
return items
@@ -297,41 +318,46 @@ export default {
297
318
if (! col || ! this .rawColumnNames .includes (col)) {
298
319
return this .tableFiltered
299
320
}
300
- // if numbers should be sorted by numeric value they all have to be valid js numbers
321
+ // if values in column are to be sorted by numeric value they all have to be type number
301
322
const flip = this .sorter .asc ? 1 : - 1
302
- return this .tableFiltered .sort ((a ,b ) => {
303
- // escape html
304
- let c = typeof a[col] === ' string' ? a[col].replace (/ <(?:. | \n )*? >/ gm , ' ' ) : a[col]
305
- let d = typeof b[col] === ' string' ? b[col].replace (/ <(?:. | \n )*? >/ gm , ' ' ) : b[col]
306
- // if (typeof c !== typeof d) {
307
- // c = String(c)
308
- // d = String(d)
309
- // }
310
- return (c > d) ? 1 * flip : ((d > c) ? - 1 * flip : 0 )
323
+ return this .tableFiltered .slice ().sort ((a ,b ) => {
324
+ return (a[col] > b[col]) ? 1 * flip : ((b[col] > a[col]) ? - 1 * flip : 0 )
311
325
})
312
326
},
327
+ firstItemIndex () {
328
+ return (this .computedPage - 1 ) * this .perPageItems || 0
329
+ },
330
+ paginatedItems () {
331
+ return this .sortedItems .slice (
332
+ this .firstItemIndex ,
333
+ this .firstItemIndex + this .perPageItems
334
+ )
335
+ },
313
336
currentItems () {
314
- if (this .computedPage ) {
315
- this .firstItemIndex = (this .computedPage - 1 ) * this .perPageItems
316
- return this .sortedItems .slice (this .firstItemIndex , this .firstItemIndex + this .perPageItems )
317
- }
318
- return this .sortedItems
337
+ return this .computedPage ? this .paginatedItems : this .sortedItems
319
338
},
320
339
totalPages () {
321
340
return Math .ceil ((this .sortedItems .length )/ this .perPageItems ) || 1
322
341
},
323
342
computedPage () {
324
343
return this .pagination ? this .page : this .activePage
325
344
},
345
+ generatedColumnNames () {
346
+ return Object .keys (this .passedItems [0 ]).filter (el => el .charAt (0 ) !== ' _' )
347
+ },
326
348
rawColumnNames () {
327
- if (this .fields )
328
- return typeof this .fields [0 ] === ' object' ? this .fields .map (el => el .key ) : this .fields
329
- return Object .keys (this .currentItems [0 ]).filter (el => el .charAt (0 ) !== ' _' )
349
+ if (this .fields ) {
350
+ return this .fields .map (el => el .key || el)
351
+ }
352
+ return this .generatedColumnNames
330
353
},
331
354
columnNames () {
332
- if (this .fields )
333
- return this .fields .map (el => el .label !== undefined ? el .label : this .columnNamePretify (el .key || el))
334
- return this .rawColumnNames .map (el => this .columnNamePretify (el))
355
+ if (this .fields ) {
356
+ return this .fields .map (f => {
357
+ return f .label !== undefined ? f .label : this .pretifyName (f .key || f)
358
+ })
359
+ }
360
+ return this .rawColumnNames .map (el => this .pretifyName (el))
335
361
},
336
362
tableClasses () {
337
363
return [
@@ -356,26 +382,28 @@ export default {
356
382
return ! this .noSorting ? ' c-position-relative c-pr-4' : ' '
357
383
},
358
384
colspan () {
359
- return this .indexColumn ? this . rawColumnNames .length + 1 : this . rawColumnNames . length
385
+ return this .rawColumnNames .length + ( this . indexColumn ? 1 : 0 )
360
386
},
361
387
topLoadingPosition () {
362
388
const headerHeight = (this .filterRow ? 38 : 0 ) + ( this .small ? 32 + 4 : 46 + 7 )
363
389
return ` top:${ headerHeight} px`
364
390
},
365
391
spinnerSize () {
366
- const size = this .small ? ' 1.4rem ' : this .currentItems .length === 1 ? ' 2rem ' : ' 3rem '
367
- return ` width:${ size} ;height:${ size} `
392
+ const size = this .small ? 1.4 : this .currentItems .length === 1 ? 2 : 3
393
+ return ` width:${ size + ' rem ' } ;height:${ size + ' rem ' } `
368
394
},
369
395
isFiltered () {
370
- return this .tableFilter || Object .keys (this .columnFilter ).filter (key => {
371
- return this .columnFilter [key]
372
- }).length
396
+ return this .tableFilter || Object .values (this .columnFilter ).join (' ' )
373
397
}
374
398
},
375
399
watch: {
376
400
items (val , oldVal ) {
377
- if (val .length !== oldVal .length || JSON .stringify (val) !== JSON .stringify (oldVal))
401
+ if (
402
+ val .length !== oldVal .length ||
403
+ JSON .stringify (val) !== JSON .stringify (oldVal)
404
+ ) {
378
405
this .passedItems = val
406
+ }
379
407
},
380
408
totalPages: {
381
409
immediate: true ,
@@ -405,35 +433,38 @@ export default {
405
433
this .sorter .asc = true
406
434
const inputs = this .$el .getElementsByClassName (' c-table-filter' )
407
435
for (let input of inputs)
408
- input .value = ' '
436
+ input .value = ' '
409
437
},
410
- columnNamePretify (name ) {
411
- const withSpaces = name .replace (/ [-_] / g , ' ' )
412
- return withSpaces .split (' ' )
413
- .map (word => word .charAt (0 ).toUpperCase () + word .slice (1 ))
414
- .join (' ' )
438
+ pretifyName (name ) {
439
+ return name .replace (/ [-_] / g , ' ' ).split (' ' ).map (word => {
440
+ return word .charAt (0 ).toUpperCase () + word .slice (1 )
441
+ }).join (' ' )
415
442
},
416
443
cellClass (item , colName , index ) {
417
444
let classes = []
418
- if (item ._cellClasses && item ._cellClasses [colName])
445
+ if (item ._cellClasses && item ._cellClasses [colName]) {
419
446
classes .push (item ._cellClasses [colName])
420
- if (this .fields && this .fields [index]._classes )
447
+ }
448
+ if (this .fields && this .fields [index]._classes ) {
421
449
classes .push (this .fields [index]._classes )
450
+ }
422
451
return classes
423
452
},
424
453
sortable (index ) {
425
454
return ! this .noSorting && (! this .fields || ! this .fields [index].noSorting )
426
455
},
427
456
headerClass (index ) {
428
- return this . fields && this .fields [index]. _classes ?
429
- this . fields [index]._classes : ' '
457
+ const fields = this .fields
458
+ return fields && fields[index]. _classes ? fields[index]._classes : ' '
430
459
},
431
460
headerStyles (index ) {
432
461
let style = ' '
433
- if (this .sortable (index))
462
+ if (this .sortable (index)) {
434
463
style += ` cursor:pointer;`
435
- if (this .fields && this .fields [index] && this .fields [index]._style )
464
+ }
465
+ if (this .fields && this .fields [index] && this .fields [index]._style ) {
436
466
style += this .fields [index]._style
467
+ }
437
468
return style
438
469
},
439
470
rowClicked (item , index ) {
@@ -456,12 +487,8 @@ export default {
456
487
paginationChange (e ) {
457
488
this .$emit (' pagination-change' , e .target .value )
458
489
this .perPageItems = Number (e .target .value )
459
- },
460
- havePaginationMenu () {
461
- return this .optionsRow !== ' noPagination' &&
462
- (this .pagination || this .$listeners [' pages-change' ])
463
490
}
464
- },
491
+ }
465
492
}
466
493
</script >
467
494
<style scoped>
0 commit comments