Skip to content

Commit

Permalink
feat(sorting): Default sorting
Browse files Browse the repository at this point in the history
Default sorting allows data to always have an implicit ordering while yielding
to any user-provided sorts. Default sorts effectively add additional columns to
the sort at the lowest priorities, they cannot be removed and automatically
reapply if the user clears their sort. Since they are intended to represent the
default state of the data the default sorts are not displayed on the column
headers and are effectively invisible to the user.
  • Loading branch information
StrangelyTyped authored and mportuga committed Apr 28, 2017
1 parent a364886 commit e629bc6
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 8 deletions.
88 changes: 88 additions & 0 deletions misc/tutorial/324_default_sorting.ngdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
@ngdoc overview
@name Tutorial: 324 Default Sorting
@description

UI-Grid allows you to apply a default sort to the data which allows you specify how the data should be ordered after any explicit sorting has been applied. This allows the data to retain a particular ordering even once the user applies an explicit sort of their own and clears any sorts initially applied through columnDef.

In this example there an initial sort via name, but the defaultSort on memberNo ensures that when the names are the same then the memberNo is used to sort the matching entries. If the name sort is removed then all the entries are automatically sorted by memberNo due to the defaultSort.

Default sorts are intended to ensure a sensible implicit ordering to the data is retained, and therefore they do not show on columnHeaders as sorts unless the user explicitly sorts by that column.

<example module="app">
<file name="app.js">
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);

app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
$scope.gridOptions = {
data: [
{ name: "David Johnson", memberNo: 6014, company: "Softsoft" },
{ name: "Brian Davidson", memberNo: 4432, company: "Roundwheel" },
{ name: "Peter Anderson", memberNo: 8725, company: "Softsoft" },
{ name: "John Johnson", memberNo: 5326, company: "Initech" },
{ name: "Andrew Thomson", memberNo: 6416, company: "Roundwheel" },
{ name: "Brian Davidson", memberNo: 9134, company: "Initech" }
],
enableSorting: true,
columnDefs: [
{ field: 'name', sort: { direction: uiGridConstants.ASC, priority: 1 } },
{ field: 'memberNo', defaultSort: { direction: uiGridConstants.ASC } },
{ field: 'company' }
],
onRegisterApi: function( gridApi ) {
$scope.grid1Api = gridApi;
}
};

}]);
</file>
<file name="index.html">
<div ng-controller="MainCtrl">
<div id="grid1" ui-grid="gridOptions" class="grid"></div>
</div>
</file>
<file name="main.css">
.grid {
width: 500px;
height: 200px;
}
</file>
<file name="scenario.js">
var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
var GridObjectTest = require('../../test/e2e/gridObjectTestUtils.spec.js');
var grid1 = new GridObjectTest('grid1');

describe('first grid on the page, default sort', function() {
// Reload the page before each test if on Firefox. Chrome does it automatically.
gridTestUtils.firefoxReload();

it('header values should be as expected', function () {
grid1.expectHeaderColumns( [ 'Name', 'Member No', 'Company' ] );
});

it('grid should be sorted by name by default', function () {
grid1.expectCellValueMatch( 0, 0, 'Andrew Thomson' );
grid1.expectCellValueMatch( 1, 0, 'Brian Davidson' );
});

it('reverse sort by name by clicking header', function () {
grid1.clickHeaderCell( 0 )
.then(function () {
grid1.expectCellValueMatch( 0, 0, 'Peter Anderson' );
grid1.expectCellValueMatch( 1, 0, 'John Johnson' );
});
});

it('remove sort and sort by memberNo by clicking header', function () {
grid1.clickHeaderCell( 0 )
.then(function () {
return grid1.clickHeaderCell( 0 );
})
.then(function () {
grid1.expectCellValueMatch( 0, 0, 'Brian Davidson' );
grid1.expectCellValueMatch( 1, 0, 'John Johnson' );
});
});

});
</file>
</example>
40 changes: 34 additions & 6 deletions src/js/core/factories/GridColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,17 @@ angular.module('ui.grid')
* <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', ariaLabel: 'Filter for text', flags: { caseSensitive: false }, type: uiGridConstants.filter.SELECT, [ { value: 1, label: 'male' }, { value: 2, label: 'female' } ] }</pre>
*
*/
/**

/**
* @ngdoc property
* @name extraStyle
* @propertyOf ui.grid.class:GridColumn
* @description additional on this column.
* @description additional on this column.
* @example
* <pre>{extraStyle: {display:'table-cell'}}</pre>
*
*/
*/

/**
* @ngdoc object
* @name ui.grid.class:GridColumn
Expand Down Expand Up @@ -208,7 +208,7 @@ angular.module('ui.grid')
GridColumn.prototype.hideColumn = function() {
this.colDef.visible = false;
};


/**
* @ngdoc method
Expand Down Expand Up @@ -320,6 +320,31 @@ angular.module('ui.grid')
*
*/

/**
* @ngdoc property
* @name defaultSort
* @propertyOf ui.grid.class:GridOptions.columnDef
* @description An object of sort information, provides a hidden default ordering of the data
* when no user sorts are applied, or when a user-provided sort deems two rows to be equal.
*
* May be combined with a regular {@link ui.grid.class:GridOptions.columnDef#properties_sort columnDef.sort}
* to explicitly sort by that column by default.
*
* Shares the same object format as {@link ui.grid.class:GridOptions.columnDef#properties_sort columnDef.sort}.
*
* Note that a defaultSort can never take priority over an explicit sort.
* @example
* <pre>
* $scope.gridOptions.columnDefs = [{
* field: 'field1',
* defaultSort: {
* direction: uiGridConstants.ASC,
* priority: 0
* }
* }];
* </pre>
*/

/**
* @ngdoc array
* @name filters
Expand Down Expand Up @@ -710,6 +735,9 @@ angular.module('ui.grid')
self.setPropertyOrDefault(colDef, 'sort');
}

// Use the column definition defaultSort always, unlike normal sort
self.setPropertyOrDefault(colDef, 'defaultSort');

// Set up default filters array for when one is not provided.
// In other words, this (in column def):
//
Expand Down
15 changes: 13 additions & 2 deletions src/js/core/services/rowSorter.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,14 +405,25 @@ module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGr

// Build the list of columns to sort by
var sortCols = [];
var defaultSortCols = [];
columns.forEach(function (col) {
if (col.sort && !col.sort.ignoreSort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
sortCols.push(col);
sortCols.push({
col: col,
sort: col.sort
});
} else if ( col.defaultSort && col.defaultSort.direction && (col.defaultSort.direction === uiGridConstants.ASC || col.defaultSort.direction === uiGridConstants.DESC) ) {
defaultSortCols.push({
col: col,
sort: col.defaultSort
});
}
});

// Sort the "sort columns" by their sort priority
sortCols = sortCols.sort(rowSorter.prioritySort);
defaultSortCols = defaultSortCols.sort(rowSorter.prioritySort);
sortCols = sortCols.concat(defaultSortCols);

// Now rows to sort by, maintain original order
if (sortCols.length === 0) {
Expand Down Expand Up @@ -440,7 +451,7 @@ module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGr

while (tem === 0 && idx < sortCols.length) {
// grab the metadata for the rest of the logic
col = sortCols[idx];
col = sortCols[idx].col;
direction = sortCols[idx].sort.direction;

sortFn = rowSorter.getSortFn(grid, col, r);
Expand Down
47 changes: 47 additions & 0 deletions test/unit/core/row-sorting.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,53 @@ describe('rowSorter', function() {

});

describe('default sort', function(){
var grid, rows, cols;

beforeEach(function() {
grid = new Grid({ id: 123 });

var e1 = { name: 'Bob', employeeId: 4 };
var e2 = { name: 'Jim', employeeId: 2 };
var e3 = { name: 'Bill', employeeId: 5 };

rows = [
new GridRow(e1, 0, grid),
new GridRow(e2, 1, grid),
new GridRow(e3, 1, grid)
];

cols = [
new GridColumn({
name: 'name',
type: 'string'
}, 0, grid),
new GridColumn({
name: 'employeeId',
type: 'string',
defaultSort: {
direction: uiGridConstants.ASC,
priority: 0
}
}, 1, grid)
];
});

it('should sort by the default sort column by default', function(){
var ret = rowSorter.sort(grid, rows, cols);

expect(ret[0].entity.name).toEqual('Jim');
});

it('should sort by the name when a sort is applied', function(){
cols[0].sort.direction = uiGridConstants.ASC;

var ret = rowSorter.sort(grid, rows, cols);
expect(ret[0].entity.name).toEqual('Bill');
});

});

describe('stable sort', function() {
var grid, rows, cols;

Expand Down

0 comments on commit e629bc6

Please sign in to comment.