Skip to content

Commit f71f9dc

Browse files
committed
feat(filter and sort): Support filter and sort by displayed value
Add getCellDisplayValue to grid core. This returns the cell value after any `cellFilter` has been applied. Add `columnDef` options `filterCellFiltered` and `sortCellFiltered`, which apply the sort and filter respectively using grid.getCellDisplayValue instead of grid.getCellValue. Close #2839 Close #3791
1 parent 2ff2cf0 commit f71f9dc

File tree

10 files changed

+174
-27
lines changed

10 files changed

+174
-27
lines changed

misc/tutorial/102_sorting.ngdoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ asynchronously after the columns it will often decide all your columns are strin
3030
column def using `type='number'`. Valid types are documented in {@link api/ui.grid.class:GridOptions.columnDef columnDef}, and
3131
include `string`, `number`, `numberStr` and `date`. If you use date be aware the code expects a javascript date object.
3232

33+
By default the sorting algorithm will be applied to the row value before any `cellFilters` are applied. The {@link api/ui.grid.class:GridOptions.columnDef#sortCellFiltered sortCellFiltered}
34+
columnDef option will cause sorting to be applied after the `cellFilters` are applied. For an example of this see the "Month Joined" column in the {@link 401_AllFeatures AllFeatures tutorial}.
35+
3336
<example module="app">
3437
<file name="app.js">
3538
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);

misc/tutorial/103_filtering.ngdoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Filtering supports dropdowns, in order to set a particular column to use a dropd
5959
and
6060
`selectOptions: [ { value: 'x', label: 'decode of x' } , .... ]`
6161

62+
6263
If you need to internationalize the labels you'll need to complete that before providing the selectOptions array.
6364

6465
### Cancel icon
@@ -72,8 +73,14 @@ In this example we've provided a "toggle filters" button to allow you to turn th
7273
still visually indicate which columns are filtered even when the filters aren't present, we've used the headerCellClass
7374
to make any columns with a filter condition have blue text.
7475

76+
### cellFilters
77+
78+
By default the filtering will not use the formatted value after applying `cellFilters`, it uses the raw value from the row. The {@link api/ui.grid.class:GridOptions.columnDef#filterCellFiltered filterCellFiltered}
79+
columnDef option will cause filtering to be applied after the `cellFilters` are evaluated, as seen on the "Long Date" field.
80+
7581
### Single filter box (similar to 2.x)
7682

83+
7784
Refer {@link 321_singleFilter singleFilter tutorial}, it is possible to implement this using a rowsProcessor.
7885

7986
@example
@@ -152,6 +159,8 @@ Refer {@link 321_singleFilter singleFilter tutorial}, it is possible to implemen
152159
placeholder: 'less than',
153160
term: nextWeek
154161
}, headerCellClass: $scope.highlightFilteredHeader
162+
},
163+
{ field: 'mixedDate', displayName: "Long Date", cellFilter: 'date:"longDate"', filterCellFiltered:true, width: '15%',
155164
}
156165
]
157166
};

misc/tutorial/401_AllFeatures.ngdoc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ All features are enabled to get an idea of performance
4848
{ name:'friends[1].name', displayName:'2nd friend', width:150, enableCellEdit: true },
4949
{ name:'friends[2].name', displayName:'3rd friend', width:150, enableCellEdit: true },
5050
{ name:'agetemplate',field:'age', width:150, cellTemplate: '<div class="ui-grid-cell-contents"><span>Age 2:{{COL_FIELD}}</span></div>' },
51-
{ name:'Is Active',field:'isActive', width:150, type:'boolean' }
51+
{ name:'Is Active',field:'isActive', width:150, type:'boolean' },
52+
{ name:'Join Date',field:'registered', cellFilter:'date', width:150, type:'date', enableFiltering:false },
53+
{ name:'Month Joined',field:'registered', cellFilter: 'date:"MMMM"', filterCellFiltered:true, sortCellFiltered:true, width:150, type:'date' }
5254
];
5355

5456
$scope.callsPending = 0;
@@ -68,6 +70,7 @@ All features are enabled to get an idea of performance
6870
data.forEach(function(row){
6971
row.id = i;
7072
i++;
73+
row.registered = new Date(row.registered)
7174
$scope.myData.push(row);
7275
});
7376
})

src/js/core/factories/Grid.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,30 @@ angular.module('ui.grid')
18301830
}
18311831
};
18321832

1833+
/**
1834+
* @ngdoc function
1835+
* @name getCellDisplayValue
1836+
* @methodOf ui.grid.class:Grid
1837+
* @description Gets the displayed value of a cell after applying any the `cellFilter`
1838+
* @param {GridRow} row Row to access
1839+
* @param {GridColumn} col Column to access
1840+
*/
1841+
Grid.prototype.getCellDisplayValue = function getCellDisplayValue(row, col) {
1842+
if ( !col.cellDisplayGetterCache ) {
1843+
var custom_filter = col.cellFilter ? " | " + col.cellFilter : "";
1844+
1845+
if (typeof(row.entity['$$' + col.uid]) !== 'undefined') {
1846+
col.cellDisplayGetterCache = $parse(row.entity['$$' + col.uid].rendered + custom_filter);
1847+
} else if (this.options.flatEntityAccess && typeof(col.field) !== 'undefined') {
1848+
col.cellDisplayGetterCache = $parse(row.entity[col.field] + custom_filter);
1849+
} else {
1850+
col.cellDisplayGetterCache = $parse(row.getEntityQualifiedColField(col) + custom_filter);
1851+
}
1852+
}
1853+
1854+
return col.cellDisplayGetterCache(row);
1855+
};
1856+
18331857

18341858
Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
18351859
var self = this,

src/js/core/factories/GridColumn.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,28 @@ angular.module('ui.grid')
582582
*/
583583
self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
584584

585+
/**
586+
* @ngdoc boolean
587+
* @name sortCellFiltered
588+
* @propertyOf ui.grid.class:GridOptions.columnDef
589+
* @description (optional) False by default. When `true` uiGrid will apply the cellFilter before
590+
* sorting the data. Note that when using this option uiGrid will assume that the displayed value is
591+
* a string, and use the {@link ui.grid.class:RowSorter#sortAlpha sortAlpha} `sortFn`. It is possible
592+
* to return a non-string value from an angularjs filter, in which case you should define a {@link ui.grid.class:GridOptions.columnDef#sortingAlgorithm sortingAlgorithm}
593+
* for the column which hanldes the returned type. You may specify one of the `sortingAlgorithms`
594+
* found in the {@link ui.grid.RowSorter rowSorter} service.
595+
*/
596+
self.sortCellFiltered = colDef.sortCellFiltered ? true : false;
597+
598+
/**
599+
* @ngdoc boolean
600+
* @name filterCellFiltered
601+
* @propertyOf ui.grid.class:GridOptions.columnDef
602+
* @description (optional) False by default. When `true` uiGrid will apply the cellFilter before
603+
* applying "search" `filters`.
604+
*/
605+
self.filterCellFiltered = colDef.filterCellFiltered ? true : false;
606+
585607
/**
586608
* @ngdoc property
587609
* @name headerCellFilter

src/js/core/services/rowSearcher.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,13 @@ module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil
181181
var term = filter.term;
182182

183183
// Get the column value for this row
184-
var value = grid.getCellValue(row, column);
184+
var value;
185+
if ( column.filterCellFiltered ){
186+
value = grid.getCellDisplayValue(row, column);
187+
} else {
188+
value = grid.getCellValue(row, column);
189+
}
190+
185191

186192
// If the filter's condition is a RegExp, then use it
187193
if (filter.condition instanceof RegExp) {

src/js/core/services/rowSorter.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGr
302302
sortFn = col.sortingAlgorithm;
303303
rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
304304
}
305+
// Always default to sortAlpha when sorting after a cellFilter
306+
else if ( col.sortCellFiltered && col.cellFilter ){
307+
sortFn = rowSorter.sortAlpha;
308+
rowSorter.colSortFnCache[col.colDef.name] = sortFn;
309+
}
305310
// Try and guess what sort function to use
306311
else {
307312
// Guess the sort function
@@ -440,8 +445,15 @@ module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGr
440445

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

443-
var propA = grid.getCellValue(rowA, col);
444-
var propB = grid.getCellValue(rowB, col);
448+
var propA, propB;
449+
450+
if ( col.sortCellFiltered ){
451+
propA = grid.getCellDisplayValue(rowA, col);
452+
propB = grid.getCellDisplayValue(rowB, col);
453+
} else {
454+
propA = grid.getCellValue(rowA, col);
455+
propB = grid.getCellValue(rowB, col);
456+
}
445457

446458
tem = sortFn(propA, propB);
447459

test/unit/core/factories/Grid.spec.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,8 @@ describe('Grid factory', function () {
523523
functionProp: function () {
524524
return 'functionPropValue';
525525
},
526-
arrayProp: ['arrayPropValue']
526+
arrayProp: ['arrayPropValue'],
527+
dateProp: new Date('2015-07-01T13:25:00+00:00') // Wednesday in July
527528
};
528529
entity['\"!weird-pro\'p'] = 'weirdPropValue';
529530

@@ -576,6 +577,29 @@ describe('Grid factory', function () {
576577
expect(grid.getCellValue(row,grid.getColumn('arrayProp'))).toBe('arrayPropValue');
577578
expect(grid.getCellValue(row,grid.getColumn('weirdProp'))).toBe('weirdPropValue');
578579

580+
expect(grid.getCellDisplayValue(row,grid.getColumn('simpleProp'))).toBe('simplePropValue');
581+
expect(grid.getCellDisplayValue(row,grid.getColumn('complexProp'))).toBe('complexPropValue');
582+
expect(grid.getCellDisplayValue(row,grid.getColumn('functionProp'))).toBe('functionPropValue');
583+
expect(grid.getCellDisplayValue(row,grid.getColumn('arrayProp'))).toBe('arrayPropValue');
584+
expect(grid.getCellDisplayValue(row,grid.getColumn('weirdProp'))).toBe('weirdPropValue');
585+
586+
});
587+
588+
it('should apply angularjs filters', function(){
589+
var colDefs = [
590+
{displayName:'date', field:'dateProp', cellFilter: 'date:"yyyy-MM-dd"'},
591+
{displayName:'weekday', field:'dateProp', cellFilter: 'date:"EEEE" | uppercase'}
592+
];
593+
var grid = new Grid({ id: 1, columnDefs:colDefs });
594+
var rows = [
595+
new GridRow(entity,1,grid)
596+
];
597+
grid.buildColumns();
598+
grid.modifyRows([entity]);
599+
600+
var row = grid.rows[0];
601+
expect(grid.getCellDisplayValue(row,grid.columns[0])).toEqual("2015-07-01");
602+
expect(grid.getCellDisplayValue(row,grid.columns[1])).toEqual("WEDNESDAY");
579603
});
580604

581605
it('not overwrite column types specified in options', function() {

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

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ describe('rowSearcher', function() {
22
var grid, $scope, $compile, recompile,
33
rows, columns, rowSearcher, uiGridConstants, filter;
44

5-
var data = [
6-
{ "name": "Ethel Price", "gender": "female", "company": "Enersol", "isActive" : true },
7-
{ "name": "Claudine Neal", "gender": "female", "company": "Sealoud", "isActive" : false },
8-
{ "name": "Beryl Rice", "gender": "female", "company": "Velity", "isActive" : true },
9-
{ "name": "Wilder Gonzales", "gender": "male", "company": "Geekko", "isActive" : false }
10-
];
11-
125
beforeEach(module('ui.grid'));
136

147
beforeEach(inject(function (_$compile_, $rootScope, _rowSearcher_, Grid, GridRow, GridColumn, _uiGridConstants_) {
@@ -22,16 +15,17 @@ describe('rowSearcher', function() {
2215
});
2316

2417
rows = grid.rows = [
25-
new GridRow({ name: 'Bill', company: 'Gruber, Inc.', age: 25, isActive: true }, 0, grid),
26-
new GridRow({ name: 'Frank', company: 'Foo Co', age: 45, isActive: false }, 1, grid),
27-
new GridRow({ name: 'Joe', company: 'Movers, Inc.', age: 0, isActive: false }, 2, grid)
18+
new GridRow({ name: 'Bill', company: 'Gruber, Inc.', age: 25, isActive: true, date: new Date('2015-07-01T13:25:00+00:00') }, 0, grid), // Wednesday
19+
new GridRow({ name: 'Frank', company: 'Foo Co', age: 45, isActive: false, date: new Date('2015-06-24T13:25:00+00:00') }, 1, grid), // Wednesday
20+
new GridRow({ name: 'Joe', company: 'Movers, Inc.', age: 0, isActive: false, date: new Date('2015-06-29T13:25:00+00:00') }, 2, grid) // Monday
2821
];
2922

3023
columns = grid.columns = [
3124
new GridColumn({ name: 'name' }, 0, grid),
3225
new GridColumn({ name: 'company' }, 1, grid),
3326
new GridColumn({ name: 'age' }, 2, grid),
34-
new GridColumn({ name: 'isActive' }, 3, grid)
27+
new GridColumn({ name: 'isActive' }, 3, grid),
28+
new GridColumn({ name: 'date' }, 4, grid)
3529
];
3630

3731
filter = null;
@@ -278,4 +272,16 @@ describe('rowSearcher', function() {
278272
});
279273
});
280274

275+
describe('with a cellFilter', function(){
276+
it('should filter by the displayed text', function(){
277+
var col = grid.columns[4];
278+
col.cellFilter = 'date:"EEEE"';
279+
col.filterCellFiltered = true;
280+
281+
setFilter(columns[4], 'Wed', uiGridConstants.filter.CONTAINS);
282+
var ret = rowSearcher.search(grid, rows, columns).filter(function(row){ return row.visible; });
283+
284+
expect(ret.length).toEqual(2);
285+
});
286+
});
281287
});

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

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
22
describe('rowSorter', function() {
33
var grid, $scope, $compile, recompile, uiGridConstants, rowSorter, gridClassFactory, Grid, GridColumn, GridRow;
44

5-
var data = [
6-
{ "name": "Ethel Price", "gender": "female", "company": "Enersol" },
7-
{ "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
8-
{ "name": "Beryl Rice", "gender": "female", "company": "Velity" },
9-
{ "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
10-
];
11-
125
beforeEach(module('ui.grid'));
136

147
beforeEach(inject(function (_$compile_, $rootScope, _uiGridConstants_, _rowSorter_, _Grid_, _GridColumn_, _GridRow_, _gridClassFactory_) {
@@ -21,10 +14,6 @@ describe('rowSorter', function() {
2114
GridRow = _GridRow_;
2215
gridClassFactory = _gridClassFactory_;
2316

24-
// $scope.gridOpts = {
25-
// data: data
26-
// };
27-
2817
// recompile = function () {
2918
// grid = angular.element('<div style="width: 500px; height: 300px" ui-grid="gridOpts"></div>');
3019
// // document.body.appendChild(grid[0]);
@@ -174,6 +163,55 @@ describe('rowSorter', function() {
174163
});
175164
});
176165

166+
describe('sort by date column', function(){
167+
var grid, rows, cols;
168+
169+
beforeEach(function() {
170+
grid = new Grid({ id: 123 });
171+
172+
var e1 = { name: 'Bob', date: new Date('2015-07-01T13:25:00+00:00') }; // Wednesday
173+
var e2 = { name: 'Jim', date: new Date('2015-06-29T13:25:00+00:00') }; // Monday
174+
var e3 = { name: 'Bill', date: new Date('2015-07-03T13:25:00+00:00') }; // Friday
175+
176+
rows = [
177+
new GridRow(e1, 0, grid),
178+
new GridRow(e2, 1, grid),
179+
new GridRow(e3, 1, grid)
180+
];
181+
182+
cols = [
183+
new GridColumn({
184+
name: 'name',
185+
type: 'string'
186+
}, 0, grid),
187+
new GridColumn({
188+
name: 'date',
189+
type: 'date',
190+
cellFilter: 'date:"EEEE"',
191+
sort: {
192+
direction: uiGridConstants.ASC,
193+
priority: 0
194+
}
195+
}, 1, grid)
196+
];
197+
});
198+
199+
it('should sort by the actual date', function(){
200+
var ret = rowSorter.sort(grid, rows, cols);
201+
202+
expect(ret[0].entity.name).toEqual('Jim');
203+
});
204+
205+
it('should sort by the day of week string', function(){
206+
cols[1].sortCellFiltered = true;
207+
208+
var ret = rowSorter.sort(grid, rows, cols);
209+
210+
expect(ret[0].entity.name).toEqual('Bill');
211+
});
212+
213+
});
214+
177215
describe('stable sort', function() {
178216
var grid, rows, cols;
179217

0 commit comments

Comments
 (0)