From 3eca46e99766eb0cc9f330948f68739dbf7d7bff Mon Sep 17 00:00:00 2001 From: Greg Maslov Date: Mon, 14 Sep 2015 16:27:25 -0700 Subject: [PATCH] feat(core): add sortDirectionCycle column option This option allows you to specify how a column's sort direction should be cycled as the heading is repeatedly clicked. The default value, [null,ASC,DESC], preserves the existing behavior. --- misc/tutorial/102_sorting.ngdoc | 4 +++ src/js/core/factories/Grid.js | 28 +++++++++--------- src/js/core/factories/GridColumn.js | 21 +++++++++++++- test/unit/core/factories/Grid.spec.js | 41 +++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/misc/tutorial/102_sorting.ngdoc b/misc/tutorial/102_sorting.ngdoc index 6f4f25207d..bf6325f819 100644 --- a/misc/tutorial/102_sorting.ngdoc +++ b/misc/tutorial/102_sorting.ngdoc @@ -25,6 +25,10 @@ data has changed by calling `gridApi.core.notifyDataChange( uiGridConstants.data If you set a default sort, you can prevent the user from removing that sort by setting `suppressRemoveSort: true` for that column. This will let the user change the direction of the sort, but take away the option to remove the sort. +When clicking on a column heading the sort direction will cycle to ascending, then descending, then back to unsorted. +You may rearrange this cycle or skip part of it by setting the +{@link api/ui.grid.class:GridOptions.columnDef#sortDirectionCycle sortDirectionCycle} columnDef option. + The sort algorithm is chosen based on the column type. ui-grid will guess the type based on the data, although if you load data asynchronously after the columns it will often decide all your columns are string. You can explicitly set the column type in the column def using `type='number'`. Valid types are documented in {@link api/ui.grid.class:GridOptions.columnDef columnDef}, and diff --git a/src/js/core/factories/Grid.js b/src/js/core/factories/Grid.js index 308ef49fd8..d4953555f1 100644 --- a/src/js/core/factories/Grid.js +++ b/src/js/core/factories/Grid.js @@ -1921,7 +1921,8 @@ angular.module('ui.grid') * Emits the sortChanged event whenever the sort criteria are changed. * @param {GridColumn} column Column to set the sorting on * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending. - * If not provided, the column will iterate through the sort directions: ascending, descending, unsorted. + * If not provided, the column will iterate through the sort directions + * specified in the {@link ui.grid.class:GridOptions.columnDef#sortDirectionCycle sortDirectionCycle} attribute. * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort * by this column only * @returns {Promise} A resolved promise that supplies the column. @@ -1955,19 +1956,20 @@ angular.module('ui.grid') } if (!direction) { - // Figure out the sort direction - if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) { - column.sort.direction = uiGridConstants.DESC; + // Find the current position in the cycle (or -1). + var i = column.sortDirectionCycle.indexOf(column.sort.direction ? column.sort.direction : null); + // Proceed to the next position in the cycle (or start at the beginning). + i = (i+1) % column.sortDirectionCycle.length; + // If suppressRemoveSort is set, and the next position in the cycle would + // remove the sort, skip it. + if (column.colDef && column.suppressRemoveSort && !column.sortDirectionCycle[i]) { + i = (i+1) % column.sortDirectionCycle.length; } - else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) { - if ( column.colDef && column.suppressRemoveSort ){ - column.sort.direction = uiGridConstants.ASC; - } else { - column.sort = {}; - } - } - else { - column.sort.direction = uiGridConstants.ASC; + + if (column.sortDirectionCycle[i]) { + column.sort.direction = column.sortDirectionCycle[i]; + } else { + column.sort = {}; } } else { diff --git a/src/js/core/factories/GridColumn.js b/src/js/core/factories/GridColumn.js index 3039c707ed..5c0153fa37 100644 --- a/src/js/core/factories/GridColumn.js +++ b/src/js/core/factories/GridColumn.js @@ -272,7 +272,7 @@ angular.module('ui.grid') * */ - /** + /** * @ngdoc property * @name sort * @propertyOf ui.grid.class:GridOptions.columnDef @@ -651,6 +651,25 @@ angular.module('ui.grid') self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true; self.sortingAlgorithm = colDef.sortingAlgorithm; + /** + * @ngdoc property + * @name sortDirectionCycle + * @propertyOf ui.grid.class:GridOptions.columnDef + * @description (optional) An array of sort directions, specifying the order that they + * should cycle through as the user repeatedly clicks on the column heading. + * The default is `[null, uiGridConstants.ASC, uiGridConstants.DESC]`. Null + * refers to the unsorted state. This does not affect the initial sort + * direction; use the {@link ui.grid.class:GridOptions.columnDef#sort sort} + * property for that. If + * {@link ui.grid.class:GridOptions.columnDef#suppressRemoveSort suppressRemoveSort} + * is also set, the unsorted state will be skipped even if it is listed here. + * Each direction may not appear in the list more than once (e.g. `[ASC, + * DESC, DESC]` is not allowed), and the list may not be empty. + */ + self.sortDirectionCycle = typeof(colDef.sortDirectionCycle) !== 'undefined' ? + colDef.sortDirectionCycle : + [null, uiGridConstants.ASC, uiGridConstants.DESC]; + /** * @ngdoc boolean * @name suppressRemoveSort diff --git a/test/unit/core/factories/Grid.spec.js b/test/unit/core/factories/Grid.spec.js index 6e8c56ecab..4f3b502dc2 100644 --- a/test/unit/core/factories/Grid.spec.js +++ b/test/unit/core/factories/Grid.spec.js @@ -786,6 +786,47 @@ describe('Grid factory', function () { expect( column.sort.priority ).toEqual(2); expect( priorColumn.sort ).toEqual({ direction: uiGridConstants.ASC, priority: 1}); }); + + it( 'if sortDirectionCycle is null-DESC-ASC, and sort is currently null, then should toggle to DESC, and reset priority', function() { + column.sort = {}; + column.sortDirectionCycle = [null, uiGridConstants.DESC, uiGridConstants.ASC]; + + grid.sortColumn( column, false ); + + expect( column.sort.direction ).toEqual(uiGridConstants.DESC); + expect( column.sort.priority ).toEqual(1); + }); + + it( 'if sortDirectionCycle is null-DESC-ASC, and sort is currently ASC, then should toggle to null, and remove priority', function() { + column.sort = {direction: uiGridConstants.ASC, priority: 1}; + column.sortDirectionCycle = [null, uiGridConstants.DESC, uiGridConstants.ASC]; + + grid.sortColumn( column, false ); + + expect( column.sort.direction ).toEqual(null); + expect( column.sort.priority ).toEqual(null); + }); + + it( 'if sortDirectionCycle is DESC, and sort is currently DESC, then should not change the sort', function() { + column.sort = {direction: uiGridConstants.DESC, priority: 1}; + column.sortDirectionCycle = [uiGridConstants.DESC]; + + grid.sortColumn( column, false ); + + expect( column.sort.direction ).toEqual(uiGridConstants.DESC); + expect( column.sort.priority ).toEqual(1); + }); + + it( 'if sortDirectionCycle is DESC-null-ASC, and sort is currently DESC, and suppressRemoveSort is true, then should toggle to ASC, and reset priority', function() { + column.sort = {direction: uiGridConstants.DESC, priority: 1}; + column.sortDirectionCycle = [uiGridConstants.DESC, null, uiGridConstants.ASC]; + column.suppressRemoveSort = true; + + grid.sortColumn( column, false ); + + expect( column.sort.direction ).toEqual(uiGridConstants.ASC); + expect( column.sort.priority ).toEqual(1); + }); });