Add front-end support for multi-column grid sorting
user must ctrl-click column header to engage multi-sort
This commit is contained in:
parent
6d7754cf2a
commit
edb5393cdc
|
@ -830,10 +830,10 @@ class Grid(object):
|
||||||
if self.sortable:
|
if self.sortable:
|
||||||
self.active_sorters = []
|
self.active_sorters = []
|
||||||
for i in range(1, settings['sorters.length'] + 1):
|
for i in range(1, settings['sorters.length'] + 1):
|
||||||
self.active_sorters.append((
|
self.active_sorters.append({
|
||||||
settings[f'sorters.{i}.key'],
|
'field': settings[f'sorters.{i}.key'],
|
||||||
settings[f'sorters.{i}.dir'],
|
'order': settings[f'sorters.{i}.dir'],
|
||||||
))
|
})
|
||||||
if self.pageable:
|
if self.pageable:
|
||||||
self.pagesize = settings['pagesize']
|
self.pagesize = settings['pagesize']
|
||||||
self.page = settings['page']
|
self.page = settings['page']
|
||||||
|
@ -1229,9 +1229,14 @@ class Grid(object):
|
||||||
if not self.active_sorters:
|
if not self.active_sorters:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
# TODO: is there a better way to check for SA sorting?
|
||||||
|
if self.model_class:
|
||||||
|
|
||||||
# convert sort settings into a 'sortspec' for use with sa-filters
|
# convert sort settings into a 'sortspec' for use with sa-filters
|
||||||
full_spec = []
|
full_spec = []
|
||||||
for sortkey, sortdir in self.active_sorters:
|
for sorter in self.active_sorters:
|
||||||
|
sortkey = sorter['field']
|
||||||
|
sortdir = sorter['order']
|
||||||
sortfunc = self.sorters.get(sortkey)
|
sortfunc = self.sorters.get(sortkey)
|
||||||
if sortfunc:
|
if sortfunc:
|
||||||
spec = {
|
spec = {
|
||||||
|
@ -1240,7 +1245,6 @@ class Grid(object):
|
||||||
'field': sortfunc._column.name,
|
'field': sortfunc._column.name,
|
||||||
'direction': sortdir or 'asc',
|
'direction': sortdir or 'asc',
|
||||||
}
|
}
|
||||||
# spec.sortkey = sortkey
|
|
||||||
full_spec.append(spec)
|
full_spec.append(spec)
|
||||||
|
|
||||||
# apply joins needed for this sort spec
|
# apply joins needed for this sort spec
|
||||||
|
@ -1252,6 +1256,26 @@ class Grid(object):
|
||||||
|
|
||||||
return apply_sort(data, full_spec)
|
return apply_sort(data, full_spec)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# not a SQLAlchemy grid, custom sorter
|
||||||
|
|
||||||
|
assert len(self.active_sorters) < 2
|
||||||
|
|
||||||
|
sortkey = self.active_sorters[0]['field']
|
||||||
|
sortdir = self.active_sorters[0]['order'] or 'asc'
|
||||||
|
|
||||||
|
# Cannot sort unless we have a sort function.
|
||||||
|
sortfunc = self.sorters.get(sortkey)
|
||||||
|
if not sortfunc:
|
||||||
|
return data
|
||||||
|
|
||||||
|
# apply joins needed for this sorter
|
||||||
|
if sortkey in self.joiners and sortkey not in self.joined:
|
||||||
|
data = self.joiners[sortkey](data)
|
||||||
|
self.joined.add(sortkey)
|
||||||
|
|
||||||
|
return sortfunc(data, sortdir)
|
||||||
|
|
||||||
def paginate_data(self, data):
|
def paginate_data(self, data):
|
||||||
"""
|
"""
|
||||||
Paginate the given data set according to current settings, and return
|
Paginate the given data set according to current settings, and return
|
||||||
|
|
|
@ -202,9 +202,25 @@
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if grid.sortable:
|
% if grid.sortable:
|
||||||
:default-sort="sortingPriority[0]"
|
|
||||||
backend-sorting
|
backend-sorting
|
||||||
@sort="onSort"
|
@sort="onSort"
|
||||||
|
@sorting-priority-removed="sortingPriorityRemoved"
|
||||||
|
|
||||||
|
## TODO: there is a bug (?) which prevents the arrow from
|
||||||
|
## displaying for simple default single-column sort. so to
|
||||||
|
## work around that, we *disable* multi-sort until the
|
||||||
|
## component is mounted. seems to work for now..see also
|
||||||
|
## https://github.com/buefy/buefy/issues/2584
|
||||||
|
:sort-multiple="allowMultiSort"
|
||||||
|
|
||||||
|
## nb. specify default sort only if single-column
|
||||||
|
:default-sort="backendSorters.length == 1 ? [backendSorters[0].field, backendSorters[0].order] : null"
|
||||||
|
|
||||||
|
## nb. otherwise there may be default multi-column sort
|
||||||
|
:sort-multiple-data="sortingPriority"
|
||||||
|
|
||||||
|
## user must ctrl-click column header to do multi-sort
|
||||||
|
sort-multiple-key="ctrlKey"
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if grid.click_handlers:
|
% if grid.click_handlers:
|
||||||
|
@ -353,7 +369,25 @@
|
||||||
lastItem: ${json.dumps(grid_data['last_item'] if grid.pageable else None)|n},
|
lastItem: ${json.dumps(grid_data['last_item'] if grid.pageable else None)|n},
|
||||||
|
|
||||||
% if grid.sortable:
|
% if grid.sortable:
|
||||||
|
|
||||||
|
## TODO: there is a bug (?) which prevents the arrow from
|
||||||
|
## displaying for simple default single-column sort. so to
|
||||||
|
## work around that, we *disable* multi-sort until the
|
||||||
|
## component is mounted. seems to work for now..see also
|
||||||
|
## https://github.com/buefy/buefy/issues/2584
|
||||||
|
allowMultiSort: false,
|
||||||
|
|
||||||
|
## nb. this contains all truly active sorters
|
||||||
|
backendSorters: ${json.dumps(grid.active_sorters)|n},
|
||||||
|
|
||||||
|
## nb. whereas this will only contain multi-column sorters,
|
||||||
|
## but will be *empty* for single-column sorting
|
||||||
|
% if len(grid.active_sorters) > 1:
|
||||||
sortingPriority: ${json.dumps(grid.active_sorters)|n},
|
sortingPriority: ${json.dumps(grid.active_sorters)|n},
|
||||||
|
% else:
|
||||||
|
sortingPriority: [],
|
||||||
|
% endif
|
||||||
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
## filterable: ${json.dumps(grid.filterable)|n},
|
## filterable: ${json.dumps(grid.filterable)|n},
|
||||||
|
@ -395,6 +429,15 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
## TODO: there is a bug (?) which prevents the arrow from
|
||||||
|
## displaying for simple default single-column sort. so to
|
||||||
|
## work around that, we *disable* multi-sort until the
|
||||||
|
## component is mounted. seems to work for now..see also
|
||||||
|
## https://github.com/buefy/buefy/issues/2584
|
||||||
|
this.allowMultiSort = true
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
% if grid.click_handlers:
|
% if grid.click_handlers:
|
||||||
|
@ -455,9 +498,9 @@
|
||||||
getBasicParams() {
|
getBasicParams() {
|
||||||
let params = {}
|
let params = {}
|
||||||
% if grid.sortable:
|
% if grid.sortable:
|
||||||
for (let i = 1; i <= this.sortingPriority.length; i++) {
|
for (let i = 1; i <= this.backendSorters.length; i++) {
|
||||||
params['sort'+i+'key'] = this.sortingPriority[i-1][0]
|
params['sort'+i+'key'] = this.backendSorters[i-1].field
|
||||||
params['sort'+i+'dir'] = this.sortingPriority[i-1][1]
|
params['sort'+i+'dir'] = this.backendSorters[i-1].order
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
% if grid.pageable:
|
% if grid.pageable:
|
||||||
|
@ -537,14 +580,45 @@
|
||||||
this.loadAsyncData()
|
this.loadAsyncData()
|
||||||
},
|
},
|
||||||
|
|
||||||
onSort(field, order) {
|
onSort(field, order, event) {
|
||||||
this.sortingPriority = [[field, order]]
|
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
|
||||||
|
// engage or enhance multi-column sorting
|
||||||
|
let sorter = this.backendSorters.filter(i => i.field === field)[0]
|
||||||
|
if (sorter) {
|
||||||
|
sorter.order = sorter.order === 'desc' ? 'asc' : 'desc'
|
||||||
|
} else {
|
||||||
|
this.backendSorters.push({field, order})
|
||||||
|
}
|
||||||
|
this.sortingPriority = this.backendSorters
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// sort by single column only
|
||||||
|
this.backendSorters = [{field, order}]
|
||||||
|
this.sortingPriority = []
|
||||||
|
}
|
||||||
|
|
||||||
// always reset to first page when changing sort options
|
// always reset to first page when changing sort options
|
||||||
// TODO: i mean..right? would we ever not want that?
|
// TODO: i mean..right? would we ever not want that?
|
||||||
this.currentPage = 1
|
this.currentPage = 1
|
||||||
this.loadAsyncData()
|
this.loadAsyncData()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sortingPriorityRemoved(field) {
|
||||||
|
|
||||||
|
// prune field from active sorters
|
||||||
|
this.backendSorters = this.backendSorters.filter(
|
||||||
|
(sorter) => sorter.field !== field)
|
||||||
|
|
||||||
|
// nb. must keep active sorter list "as-is" even if
|
||||||
|
// there is only one sorter; buefy seems to expect it
|
||||||
|
this.sortingPriority = this.backendSorters
|
||||||
|
|
||||||
|
this.loadAsyncData()
|
||||||
|
},
|
||||||
|
|
||||||
resetView() {
|
resetView() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue