Skip to content

Commit 3ee6adf

Browse files
committed
feat: CDataTable new functionalities:
- tableFIlter, columnFilter, sorter props now have configuration objects (passing String is removed). - scoped function classes added to sorting-icon slot - delete 'table-filter-input' and 'column-filter-input' events
1 parent cf69e75 commit 3ee6adf

File tree

4 files changed

+142
-147
lines changed

4 files changed

+142
-147
lines changed

src/components/index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,8 @@ export declare class CDataTable extends Vue {
540540
outlined: boolean
541541
optionsRow: [boolean, string]
542542
footer: boolean
543-
sorter: [boolean, string]
544-
columnFilter: [boolean, string]
543+
sorter: [boolean, object]
544+
columnFilter: [boolean, object]
545545
tableFilter: [boolean, object]
546546
sorterValue: object
547547
tableFilterValue: string

src/components/table/CDataTable.vue

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
class="form-control table-filter"
1111
type="text"
1212
:placeholder="tableFilterData.placeholder"
13-
@input="tableFilterChange($event.target.value)"
13+
@input="tableFilterChange($event.target.value, 'input')"
1414
@change="tableFilterChange($event.target.value, 'change')"
1515
:value="tableFilterState"
1616
>
@@ -62,6 +62,7 @@
6262
v-if="isSortable(index)"
6363
name="sorting-icon"
6464
:state="getIconState(index)"
65+
:classes="iconClasses(index)"
6566
>
6667
<CIcon
6768
width="18"
@@ -244,9 +245,9 @@ export default {
244245
border: Boolean,
245246
outlined: Boolean,
246247
itemsPerPageSelect: Boolean,
247-
sorter: [Boolean, String],
248+
sorter: [Boolean, Object],
248249
tableFilter: [Boolean, Object],
249-
columnFilter: [Boolean, String],
250+
columnFilter: [Boolean, Object],
250251
sorterValue: {
251252
type: Object,
252253
default: () => { return {} }
@@ -308,9 +309,12 @@ export default {
308309
computed: {
309310
columnFiltered () {
310311
let items = this.passedItems.slice()
312+
if (this.columnFilter && this.columnFilter.external) {
313+
return items
314+
}
311315
Object.entries(this.columnFilterState).forEach(([key, value]) => {
312-
if (value && this.rawColumnNames.includes(key)) {
313-
const columnFilter = String(value).toLowerCase()
316+
const columnFilter = String(value).toLowerCase()
317+
if (columnFilter && this.rawColumnNames.includes(key)) {
314318
items = items.filter(item => {
315319
return String(item[key]).toLowerCase().includes(columnFilter)
316320
})
@@ -325,18 +329,19 @@ export default {
325329
},
326330
tableFiltered () {
327331
let items = this.columnFiltered.slice()
328-
if (this.tableFilterState) {
329-
const filter = this.tableFilterState.toLowerCase()
330-
const hasFilter = (item) => String(item).toLowerCase().includes(filter)
331-
items = items.filter(item => {
332-
return this.filterableCols.filter(key => hasFilter(item[key])).length
333-
})
332+
if (!this.tableFilterState || (this.tableFilter && this.tableFilter.external)) {
333+
return items
334334
}
335+
const filter = this.tableFilterState.toLowerCase()
336+
const hasFilter = (item) => String(item).toLowerCase().includes(filter)
337+
items = items.filter(item => {
338+
return this.filterableCols.filter(key => hasFilter(item[key])).length
339+
})
335340
return items
336341
},
337342
sortedItems () {
338343
const col = this.sorterState.column
339-
if (!col || !this.rawColumnNames.includes(col)) {
344+
if (!col || !this.rawColumnNames.includes(col) || this.sorter.external) {
340345
return this.tableFiltered
341346
}
342347
//if values in column are to be sorted by numeric value they all have to be type number
@@ -410,27 +415,35 @@ export default {
410415
},
411416
methods: {
412417
changeSort (column, index) {
413-
if (column && !this.isSortable(index)) {
418+
if (!this.isSortable(index)) {
414419
return
415420
}
416421
//if column changed or sort was descending change asc to true
417422
const state = this.sorterState
418-
state.asc = state.column !== column || !state.asc
419-
state.column = column
423+
const columnRepeated = state.column === column
424+
if (!this.sorter || !this.sorter.resetable) {
425+
state.column = column
426+
} else {
427+
state.column = columnRepeated && state.asc === false ? undefined : column
428+
}
429+
state.asc = !(columnRepeated && state.asc)
420430
this.$emit('update:sorter-value', this.sorterState)
421431
},
422432
columnFilterEvent (colName, value, type) {
423-
this.setColumnFilter(colName, value)
424-
const e = type === 'input' ? 'column-filter-input' : 'update:column-filter-value'
425-
this.$emit(e, this.columnFilterState)
426-
},
427-
setColumnFilter (colName, value) {
433+
const isLazy = this.columnFilter && this.columnFilter.lazy === true
434+
if (isLazy && type === 'input' || !isLazy && type === 'change') {
435+
return
436+
}
428437
this.$set(this.columnFilterState, colName, value)
438+
this.$emit('update:column-filter-value', this.tableFilterState)
429439
},
430-
tableFilterChange (value, type = 'input') {
440+
tableFilterChange (value, type) {
441+
const isLazy = this.tableFilter && this.tableFilter.lazy === true
442+
if (isLazy && type === 'input' || !isLazy && type === 'change') {
443+
return
444+
}
431445
this.tableFilterState = value
432-
const e = type === 'input' ? 'table-filter-input' : 'update:table-filter-value'
433-
this.$emit(e, this.tableFilterState)
446+
this.$emit('update:table-filter-value', this.tableFilterState)
434447
},
435448
pretifyName (name) {
436449
return name.replace(/[-_.]/g, ' ')
@@ -507,7 +520,7 @@ export default {
507520
transform: translateY(-50%);
508521
}
509522
.rotate-icon {
510-
-ms-transform: translateY(-50%) rotate(-180deg);
523+
-ms-transform: translateY(-50%) rotate(-180deg);
511524
transform: translateY(-50%) rotate(-180deg);
512525
}
513526
</style>

src/components/table/tests/CDataTable.spec.js

Lines changed: 94 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,45 @@ const items = [
1111
{username: 'Yiorgos Avraamu', registered: '2012/01/01', role: 'Member', status: 'Active'},
1212
{
1313
username: 'Friderik Dávid',
14-
registered: '2012/01/21',
14+
registered: '2011/01/21',
1515
role: 'Staff',
1616
status: 'Active',
1717
_cellClasses: { registered: 'custom-cell-class' }
1818
},
1919
]
20+
const customWrapper = createCustomWrapper()
2021

21-
const customWrapper = mount(Component, {
22-
propsData: {
23-
items,
24-
fields: [
25-
{ key: 'username', _style:'width:40%', _classes: 'user-custom-class' },
26-
'registered',
27-
{ key: 'role', _style:'width:20%;' },
28-
{ key: 'status', _style:'width:20%;' },
29-
{ key: 'show_details' , label:'', _style:'width:1%', sorter: false, filter: false },
30-
],
22+
function createCustomWrapper () {
23+
return mount(Component, {
24+
propsData: {
25+
items,
26+
fields: [
27+
{ key: 'username', _style:'width:40%', _classes: 'user-custom-class' },
28+
'registered',
29+
{ key: 'role', _style:'width:20%;' },
30+
{ key: 'status', _style:'width:20%;' },
31+
{ key: 'show_details' , label:'', _style:'width:1%', sorter: false, filter: false },
32+
],
3133

32-
tableFilter: true,
33-
itemsPerPageSelect: true,
34-
addTableClasses: 'additional-table-class',
35-
sorter: true,
36-
small: false,
37-
dark: true,
38-
striped: true,
39-
fixed: false,
40-
hover: true,
41-
border: true,
42-
outlined: true,
43-
columnFilter: true,
44-
footer: true,
45-
sorterValue: { column: 'username', asc: false },
46-
columnFilterValue: { registered: '2012', 'non_existing': 'smh' },
47-
pagination: true
48-
}
49-
})
34+
tableFilter: true,
35+
itemsPerPageSelect: true,
36+
addTableClasses: 'additional-table-class',
37+
sorter: true,
38+
small: false,
39+
dark: true,
40+
striped: true,
41+
fixed: false,
42+
hover: true,
43+
border: true,
44+
outlined: true,
45+
columnFilter: true,
46+
footer: true,
47+
sorterValue: { column: 'username', asc: false },
48+
columnFilterValue: { registered: '2012', 'non_existing': 'smh' },
49+
pagination: true
50+
}
51+
})
52+
}
5053

5154
describe(ComponentName, () => {
5255
it('has a name', () => {
@@ -90,31 +93,36 @@ describe(ComponentName, () => {
9093
})
9194
it('correctly updates items', () => {
9295
//test if watcher is not fired by coverage
93-
customWrapper.setProps({ items: items.slice() })
94-
expect(customWrapper.vm.sortedItems.length).toBe(5)
95-
96-
const newItems = items.slice(0, 4)
97-
customWrapper.setProps({ items: newItems })
98-
expect(customWrapper.vm.sortedItems.length).toBe(4)
99-
})
100-
it('triggers proper events on column input change', () => {
101-
const input = customWrapper.findAll('tr').at(1).find('input')
102-
const changeEmmited = () => customWrapper.emitted()['update:column-filter-value']
103-
const inputEmmited = () => customWrapper.emitted()['column-filter-input']
96+
const localWrapper = createCustomWrapper()
97+
localWrapper.setProps({ items: items.slice() })
98+
expect(localWrapper.vm.sortedItems.length).toBe(4)
10499

105-
expect(changeEmmited()).not.toBeTruthy()
106-
expect(inputEmmited()).not.toBeTruthy()
107-
input.trigger('change')
108-
expect(changeEmmited()).toBeTruthy()
100+
const newItems = items.slice(0, 2)
101+
localWrapper.setProps({ items: newItems })
102+
expect(localWrapper.vm.sortedItems.length).toBe(2)
103+
})
104+
it('updates column filter on events depending on lazy modifier', () => {
105+
const localWrapper = createCustomWrapper()
106+
const input = localWrapper.findAll('tr').at(1).find('input')
107+
const updateEmmited = () => localWrapper.emitted()['update:column-filter-value']
108+
localWrapper.setProps({ columnFilter: { lazy: true } })
109109
input.trigger('input')
110-
expect(inputEmmited()).toBeTruthy()
110+
expect(updateEmmited()).not.toBeTruthy()
111+
localWrapper.setProps({ columnFilter: true })
112+
input.trigger('input')
113+
expect(updateEmmited()).toBeTruthy()
111114
})
112-
it('correctly filter by table filter after input or change event', () => {
113-
const input = customWrapper.find('input')
114-
const firstUsername = () => customWrapper.vm.sortedItems[0].username
115-
input.setValue('Estavan')
115+
it('updates table filter on events depending on lazy modifier', () => {
116+
const localWrapper = createCustomWrapper()
117+
const input = localWrapper.find('input')
118+
const firstUsername = () => localWrapper.vm.sortedItems[0].username
119+
input.element.value = "Estavan"
120+
input.trigger('input')
116121
expect(firstUsername()).toMatch('Estavan')
122+
localWrapper.setProps({ tableFilter: { lazy: true } })
117123
input.element.value = "Chetan"
124+
input.trigger('input')
125+
expect(firstUsername()).toMatch('Estavan')
118126
input.trigger('change')
119127
expect(firstUsername()).toMatch('Chetan')
120128
})
@@ -128,10 +136,41 @@ describe(ComponentName, () => {
128136
})
129137
expect(customWrapper.vm.perPageItems).toBe(13)
130138
})
131-
// it('Sets table filter data correctly', () => {
132-
// customWrapper.setProps({
133-
// tableFilter: { label: 'label'}
134-
// })
135-
// expect(customWrapper.vm.tableFilterData.label).toBe('label')
136-
// })
139+
it('Disable component sorting and filtering when using \'external\' keys', () => {
140+
const localWrapper = createCustomWrapper()
141+
localWrapper.setProps({
142+
tableFilterValue: 'Yiorgos'
143+
})
144+
expect(localWrapper.vm.sortedItems.length).toBe(1)
145+
localWrapper.setProps({
146+
tableFilter: { external: true }
147+
})
148+
expect(localWrapper.vm.sortedItems.length).toBe(4)
149+
150+
localWrapper.setProps({
151+
columnFilter: { external: true },
152+
})
153+
expect(localWrapper.vm.sortedItems.length).toBe(5)
154+
155+
expect(localWrapper.vm.sortedItems[0].username).toBe('Yiorgos Avraamu')
156+
localWrapper.setProps({
157+
sorter: { external: true }
158+
})
159+
expect(localWrapper.vm.sortedItems[0].username).toBe('Estavan Lykos')
160+
})
161+
it('Sorter reset mechanism is working properly', () => {
162+
const localWrapper = createCustomWrapper()
163+
const click = (clickCount = 1) => {
164+
for (let i = 0; i < clickCount; i++) {
165+
localWrapper.find('tr').findAll('th').at(2).trigger('click')
166+
}
167+
}
168+
localWrapper.setProps({
169+
sorter: { resetable : true }
170+
})
171+
click(3)
172+
expect(localWrapper.vm.sorterState.column).toBe(undefined)
173+
click(2)
174+
expect(localWrapper.vm.sorterState.asc).toBe(false)
175+
})
137176
})

0 commit comments

Comments
 (0)