Skip to content

Commit e629bc6

Browse files
StrangelyTypedmportuga
authored andcommitted
feat(sorting): Default sorting
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.
1 parent a364886 commit e629bc6

File tree

4 files changed

+182
-8
lines changed

4 files changed

+182
-8
lines changed
+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
@ngdoc overview
2+
@name Tutorial: 324 Default Sorting
3+
@description
4+
5+
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.
6+
7+
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.
8+
9+
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.
10+
11+
<example module="app">
12+
<file name="app.js">
13+
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
14+
15+
app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
16+
$scope.gridOptions = {
17+
data: [
18+
{ name: "David Johnson", memberNo: 6014, company: "Softsoft" },
19+
{ name: "Brian Davidson", memberNo: 4432, company: "Roundwheel" },
20+
{ name: "Peter Anderson", memberNo: 8725, company: "Softsoft" },
21+
{ name: "John Johnson", memberNo: 5326, company: "Initech" },
22+
{ name: "Andrew Thomson", memberNo: 6416, company: "Roundwheel" },
23+
{ name: "Brian Davidson", memberNo: 9134, company: "Initech" }
24+
],
25+
enableSorting: true,
26+
columnDefs: [
27+
{ field: 'name', sort: { direction: uiGridConstants.ASC, priority: 1 } },
28+
{ field: 'memberNo', defaultSort: { direction: uiGridConstants.ASC } },
29+
{ field: 'company' }
30+
],
31+
onRegisterApi: function( gridApi ) {
32+
$scope.grid1Api = gridApi;
33+
}
34+
};
35+
36+
}]);
37+
</file>
38+
<file name="index.html">
39+
<div ng-controller="MainCtrl">
40+
<div id="grid1" ui-grid="gridOptions" class="grid"></div>
41+
</div>
42+
</file>
43+
<file name="main.css">
44+
.grid {
45+
width: 500px;
46+
height: 200px;
47+
}
48+
</file>
49+
<file name="scenario.js">
50+
var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
51+
var GridObjectTest = require('../../test/e2e/gridObjectTestUtils.spec.js');
52+
var grid1 = new GridObjectTest('grid1');
53+
54+
describe('first grid on the page, default sort', function() {
55+
// Reload the page before each test if on Firefox. Chrome does it automatically.
56+
gridTestUtils.firefoxReload();
57+
58+
it('header values should be as expected', function () {
59+
grid1.expectHeaderColumns( [ 'Name', 'Member No', 'Company' ] );
60+
});
61+
62+
it('grid should be sorted by name by default', function () {
63+
grid1.expectCellValueMatch( 0, 0, 'Andrew Thomson' );
64+
grid1.expectCellValueMatch( 1, 0, 'Brian Davidson' );
65+
});
66+
67+
it('reverse sort by name by clicking header', function () {
68+
grid1.clickHeaderCell( 0 )
69+
.then(function () {
70+
grid1.expectCellValueMatch( 0, 0, 'Peter Anderson' );
71+
grid1.expectCellValueMatch( 1, 0, 'John Johnson' );
72+
});
73+
});
74+
75+
it('remove sort and sort by memberNo by clicking header', function () {
76+
grid1.clickHeaderCell( 0 )
77+
.then(function () {
78+
return grid1.clickHeaderCell( 0 );
79+
})
80+
.then(function () {
81+
grid1.expectCellValueMatch( 0, 0, 'Brian Davidson' );
82+
grid1.expectCellValueMatch( 1, 0, 'John Johnson' );
83+
});
84+
});
85+
86+
});
87+
</file>
88+
</example>

src/js/core/factories/GridColumn.js

+34-6
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,17 @@ angular.module('ui.grid')
8181
* <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>
8282
*
8383
*/
84-
85-
/**
84+
85+
/**
8686
* @ngdoc property
8787
* @name extraStyle
8888
* @propertyOf ui.grid.class:GridColumn
89-
* @description additional on this column.
89+
* @description additional on this column.
9090
* @example
9191
* <pre>{extraStyle: {display:'table-cell'}}</pre>
9292
*
93-
*/
94-
93+
*/
94+
9595
/**
9696
* @ngdoc object
9797
* @name ui.grid.class:GridColumn
@@ -208,7 +208,7 @@ angular.module('ui.grid')
208208
GridColumn.prototype.hideColumn = function() {
209209
this.colDef.visible = false;
210210
};
211-
211+
212212

213213
/**
214214
* @ngdoc method
@@ -320,6 +320,31 @@ angular.module('ui.grid')
320320
*
321321
*/
322322

323+
/**
324+
* @ngdoc property
325+
* @name defaultSort
326+
* @propertyOf ui.grid.class:GridOptions.columnDef
327+
* @description An object of sort information, provides a hidden default ordering of the data
328+
* when no user sorts are applied, or when a user-provided sort deems two rows to be equal.
329+
*
330+
* May be combined with a regular {@link ui.grid.class:GridOptions.columnDef#properties_sort columnDef.sort}
331+
* to explicitly sort by that column by default.
332+
*
333+
* Shares the same object format as {@link ui.grid.class:GridOptions.columnDef#properties_sort columnDef.sort}.
334+
*
335+
* Note that a defaultSort can never take priority over an explicit sort.
336+
* @example
337+
* <pre>
338+
* $scope.gridOptions.columnDefs = [{
339+
* field: 'field1',
340+
* defaultSort: {
341+
* direction: uiGridConstants.ASC,
342+
* priority: 0
343+
* }
344+
* }];
345+
* </pre>
346+
*/
347+
323348
/**
324349
* @ngdoc array
325350
* @name filters
@@ -710,6 +735,9 @@ angular.module('ui.grid')
710735
self.setPropertyOrDefault(colDef, 'sort');
711736
}
712737

738+
// Use the column definition defaultSort always, unlike normal sort
739+
self.setPropertyOrDefault(colDef, 'defaultSort');
740+
713741
// Set up default filters array for when one is not provided.
714742
// In other words, this (in column def):
715743
//

src/js/core/services/rowSorter.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -405,14 +405,25 @@ module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGr
405405

406406
// Build the list of columns to sort by
407407
var sortCols = [];
408+
var defaultSortCols = [];
408409
columns.forEach(function (col) {
409410
if (col.sort && !col.sort.ignoreSort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
410-
sortCols.push(col);
411+
sortCols.push({
412+
col: col,
413+
sort: col.sort
414+
});
415+
} else if ( col.defaultSort && col.defaultSort.direction && (col.defaultSort.direction === uiGridConstants.ASC || col.defaultSort.direction === uiGridConstants.DESC) ) {
416+
defaultSortCols.push({
417+
col: col,
418+
sort: col.defaultSort
419+
});
411420
}
412421
});
413422

414423
// Sort the "sort columns" by their sort priority
415424
sortCols = sortCols.sort(rowSorter.prioritySort);
425+
defaultSortCols = defaultSortCols.sort(rowSorter.prioritySort);
426+
sortCols = sortCols.concat(defaultSortCols);
416427

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

441452
while (tem === 0 && idx < sortCols.length) {
442453
// grab the metadata for the rest of the logic
443-
col = sortCols[idx];
454+
col = sortCols[idx].col;
444455
direction = sortCols[idx].sort.direction;
445456

446457
sortFn = rowSorter.getSortFn(grid, col, r);

test/unit/core/row-sorting.spec.js

+47
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,53 @@ describe('rowSorter', function() {
212212

213213
});
214214

215+
describe('default sort', function(){
216+
var grid, rows, cols;
217+
218+
beforeEach(function() {
219+
grid = new Grid({ id: 123 });
220+
221+
var e1 = { name: 'Bob', employeeId: 4 };
222+
var e2 = { name: 'Jim', employeeId: 2 };
223+
var e3 = { name: 'Bill', employeeId: 5 };
224+
225+
rows = [
226+
new GridRow(e1, 0, grid),
227+
new GridRow(e2, 1, grid),
228+
new GridRow(e3, 1, grid)
229+
];
230+
231+
cols = [
232+
new GridColumn({
233+
name: 'name',
234+
type: 'string'
235+
}, 0, grid),
236+
new GridColumn({
237+
name: 'employeeId',
238+
type: 'string',
239+
defaultSort: {
240+
direction: uiGridConstants.ASC,
241+
priority: 0
242+
}
243+
}, 1, grid)
244+
];
245+
});
246+
247+
it('should sort by the default sort column by default', function(){
248+
var ret = rowSorter.sort(grid, rows, cols);
249+
250+
expect(ret[0].entity.name).toEqual('Jim');
251+
});
252+
253+
it('should sort by the name when a sort is applied', function(){
254+
cols[0].sort.direction = uiGridConstants.ASC;
255+
256+
var ret = rowSorter.sort(grid, rows, cols);
257+
expect(ret[0].entity.name).toEqual('Bill');
258+
});
259+
260+
});
261+
215262
describe('stable sort', function() {
216263
var grid, rows, cols;
217264

0 commit comments

Comments
 (0)