md-data-table
md-data-table copied to clipboard
Multiple column ordering
It would be nice if there was a possibility of sorting/ordering on more than one column at a time.
From JSON:API:
An endpoint MAY support multiple sort fields by allowing comma-separated (U+002C COMMA, ",") sort fields. Sort fields SHOULD be applied in the order specified.
GET /people?sort=age,name HTTP/1.1 Accept: application/vnd.api+json
The sort order for each sort field MUST be ascending unless it is prefixed with a minus (U+002D HYPHEN-MINUS, "-"), in which case it MUST be descending.
GET /articles?sort=-created,title HTTP/1.1 Accept: application/vnd.api+json
The above example should return the newest articles first. Any articles created on the same date will then be sorted by their title in ascending alphabetical order.
Hmm... this might be tricky. It looks like ng-repeat
supports ordering by multiple properties with the following syntax,
<div ng-repeat="item in items | orderBy: ['one', 'two']">
My first thought is, how do you control multi-column sorting in the UI in a way that is obvious to the user?
In my case i'm ordering server side - does this make a difference to you ?
I was thinking that the order should be applied in the order it was clicked.
ie -> click name
then id
would sort by "name" then by "ID"
if after that you re-click name
, then you would sort by ID and then by name.
clicking twice the same thing would change ascending/descending.
In my case i'm ordering server side - does this make a difference to you ?
No, we just need to make sure it is compatible with ng-repeat
. I think setting the order
as an array of strings is fine. If the developer needs a different format for their query language they can just process the array in their md-trigger
function.
I was thinking that the order should be applied in the order it was clicked.
ie -> click name then id would sort by "name" then by "ID" if after that you re-click name, then you would sort by ID and then by name.
clicking twice the same thing would change ascending/descending.
The issue is, the user needs a way of controlling whether clicking a second column mean to sort using both columns or to only sort on the column they just clicked. Otherwise the array of items to sort on would grow without restriction.
We need some way of requiring the user to indicate that they would like to sort on multiple columns, maybe require them to hold the command key as they click multiple columns? I don't know if that would be obvious to the user or not.
I guess the CTRL + Click option is a good one, you could leave the actual explanation to the front end dev.
I'd suggest using a 3-state switch for sorting instead of a modifier key so it can be done on mobile devices as well. So it would go in this order: ascending, descending, no sort.
And the order of sorting is of course as @jsenecal suggested:
ie -> click name then id would sort by "name" then by "ID" if after that you re-click name, then you would sort by ID and then by name.
But it would be a nice thing to have some sort of a visual representation of this. A small number next to the sort arrow maybe, like the one mentioned here: http://ux.stackexchange.com/a/34790/2538
@gligoran the three-state switch is an option, not an option that I am very fond of but it would work on mobile where as the key + click option would not.
We can't necessarily enforce the [ascending, descending, no sort.] order. It may be beneficial for some applications to first sort descending so we would need to provide that as an option.
If we are concerned about multi-column sort on mobile then key + click is out
With the way things are developing everywhere at the moment, I think mobile should have the same capabilities as a desktop PC.
Of course that should be configurable, I was trying to show what I mean by 3-state.
I agree, I believe developing apps for mobile browsers is just as important as developing apps for desktop browsers. The irony though is that data tables are inherently bad for mobile devices. I really question, from a UX perspective, if tables should be used at all on mobile devices.
@gligoran +1 for your tri-state idea - it seams like the perfect behavior but I think it should be debounced to prevent API calls when cycling the options ...
datatables and ui-grid are using shift-click for multiple column ordering/sorting.
On a click, sort list is cleared and only one column is sorted. On a shift-click, tri-state for the column is changed and column is added to the sort list if not present. state "no sort" removes the column from the sort list.
See: https://datatables.net/examples/basic_init/multi_col_sort.html http://ui-grid.info/docs/#/tutorial/102_sorting
@antoinebrault shift-click will not work on devices without a keyboard. Maybe we could use a gesture on mobile? For example, double tap to add a column to the sort list.
@daniel-nagy Yeah I think you could figure out something for mobile devices. However, I don't think you should restrict desktop features based on the fact that it's hard to use on mobile. Maybe you could support multiple column ordering in general, bind shift-click for desktop and make another issue to figure out later how to do it for mobile (switch, gesture, etc.)
@antoinebrault That is probably what I will do, I just want to make sure when I (or someone else if they want :smiley:) develop this we isolate the logic from the actual method for triggering it so we can easily go back later and make it work with mobile.
We also need to think about how we are going to detect mobile devices without included additional libraries. Maybe checking for touch events on the window object is sufficient.
Do you actually have to determine what kind of a device it is? I'm thinking that you could have both SHIFT click and double click/tap work side by side. This way you cover all devices without knowing their type and add desktop users an additional option how to multi-sort.
@gligoran You wouldn't need to check for a specific device necessarily but I don't think it would be wise to register listeners for touch events if they are not defined in the browser. While it may not have much of an effect on performance, I think it would be better to not make the browser do more work than it needs to.
@daniel-nagy , Has this been implemented Daniel? I am also in need of this feature..
I think like @jsenecal. CTRL + Click is a good one. I want too this feature.
Hi, any update on that feature?
Any news about it? I still need multi-column ordering
Hi. Any news about this feature?
I am in need of this feature too. I really like the implementation of the rest of the component. Would love to have this implemented. Any word on if it is being worked on or the state it is in?
Using Bootstrap and Lodash.... For multi-column server-side ordering with this tool, I disabled the sort display in the column headers, then show a list of buttons of the current sort order, green with an up caret or red with a down caret. When you click on one of these buttons, it removes the sort. If you click on a column, it either adds the field to the sort, makes it the first field to sort by, or inverses the sort order if it's already the first field to sort by. I have done 3-column background sort column colors instead, but this is what I've done with this particular tool.
$scope.sort = [];
$scope.removeSort = function (item) {
if (item) $scope.sort = _.filter($scope.sort, s => {
return s !== item;
});
$scope.applySort();
}
$scope.orderData = function (field) {
var target = field.indexOf('-') == 0 ? field.substr(1): field;
$scope.sort = _.filter($scope.sort, s => {
return s !== target && s != '-' + target;
})
$scope.sort.unshift(field);
$scope.applySort();
}
$scope.applySort = function () {
$scope.criteria.sorts = _.map($scope.sort, (d) => {
var field = d.indexOf('-') === 0 ? d.substr(1): d;
var direction = d.indexOf('-') === 0 ? 'DESC': 'ASC';
return { attribute: field, order: direction };
});
$scope.loadData();
}
Then I make my buttons like this (inside a toolbar):
<span class="filtersList pull-right m-l-lg m-b-sm" ng-if="sort.length>0">
<span class="title m-r-xs">Sorting:</span>
<span ng-repeat="item in sort" ng-init="sortAsc = item.indexOf('-') !== 0; sortName = sortAsc ? item: item.slice(1)">
<button class="btn btn-xs m-l-xs" ng-class="sortAsc ? 'btn-danger': 'btn-info'" ng-click="removeSort(item)"><i class="fa m-r-xs" ng-class="sortAsc ? 'fa-chevron-down':'fa-chevron-up'"></i>{{ sortName }}</button>
</span>
</span>
Inside my md-table, I do this:
<thead md-head md-order="order" md-on-reorder="orderData">
I've got added complexity in the orderData process because my server for this particular project wants the sort array expressed as an array of objects instead of an array of field-name strings.