LIDOR SYSTEMS

Advanced User Interface Controls and Components

AngularJS Grid with Custom Sorting

Created: 31 July 2015

By default sorting in AngularJS Grid is disabled. In following sections of this article we will show you how to enable sorting based on which column is selected, using built-in sorting and for some columns by creating a custom sort operation.

Grid directive is part of IntegralUI Studio for Web
a suite of UI Components for development of web apps

In order to process a sort operation, at first we need to determine the sort order, which can be one of the following: 'none', 'ascending' or 'descending'. Then we also need to determine by which column rows will be sorted. This can be set manually or in case of our example, whenever a column is clicked.

In above demonstration, whenever a column is selected, the order of rows will be changed based on the cell text or value, that belong to clicked column. Initially, we manually select the first column in the grid, and rows are sorted in ascending order.

angular

.module("appModule", ["integralui"])

.controller("appCtrl", ["$scope", "IntegralUITreeGridService", "$timeout", function($scope, $gridService, $timeout){

var initTimer = $timeout(function(){

sortColumn = $scope.columns[0];

 

$scope.sorting = 'ascending';

$gridService.selectedColumn($scope.gridName, sortColumn);

$gridService.sort($scope.gridName, sortColumn, $scope.sorting);

 

prevColumn = sortColumn;

 

$timeout.cancel(initTimer);

}, 1);

}]);

Whenever a new column is clicked, the sort order will remain the same, but now rows will become sorted using the values of cells in clicked column. The sort order will change only if the column is clicked twice. The right side of sorting column header, displays an icon showing the sort order.

Built-in Sorting

Grid directive for AngularJS supports sorting of general value types: string, numeric, boolean etc. If a column contains a generic value, you can use the built-in sort operations, which will automatically sort all rows in the grid. Rows are sorted using their cell text or value that belongs to sorting column. If the value is not provided, the cell text is used.

For example, the second column 'Population' display cells with numeric values. But in order to process sorting based on numeric values, we must set a numeric value in each cell. Here how this looks like in code:

$scope.rows = [

{

id: 1,

text: "Africa",

cells: [{ cid: 2, text: "Africa" }],

rows: [

{ id: 11, pid: 1, text: "Egypt", cells: [{ cid: 2, text: "Egypt" }, { cid: 3, text: "88,311,000", value: 88311000 }, { cid: 4, text: "06 Apr 2015", value: new Date(2015, 3, 6) }, { cid: 6, text: "995,450", value: 995450 }, { cid: 7, text: "Cairo" }] },

{ id: 12, pid: 1, text: "Nigeria", cells: [{ cid: 2, text: "Nigeria" }, { cid: 3, text: "185,043,000", value: 185043000 }, { cid: 4, text: "01 Jul 2015", value: new Date(2015, 6, 1) }, { cid: 6, text: "910,768", value: 910768 }, { cid: 7, text: "Abuja" }] },

{ id: 13, pid: 1, text: "South Africa", cells: [{ cid: 2, text: "South Africa" }, { cid: 3, text: "54,002,000", value: 54002000 }, { cid: 4, text: "01 Jul 2014", value: new Date(2014, 6, 1) }, { cid: 6, text: "1,214,470", value: 1214470 }, { cid: 7, text: "Pretoria" }] }

]

}

];

The cell with cid set to 3, contains both text and value fields. Because value field is set, when sorting is process it will be used instead of its text. This allows a cell to display its value in formatted string, while still keeping its original value in numeric format.

Now that we have set up our grid structure, we can handle the columnClick event and call the sort method to process sorting based on which column is clicked.

$scope.sorting = 'none';

var sortColumn = null;

var prevColumn = null;

 

// Handler for columnClick event in AngularJS Grid directive

$scope.onColumnClick = function(e){

if (e.column){

if (e.column != prevColumn){

if ($scope.sorting == 'none')

$scope.sorting = 'ascending';

}

else {

if ($scope.sorting == 'ascending')

$scope.sorting = 'descending';

else

$scope.sorting = 'ascending';

}

 

sortColumn = e.column;

prevColumn = e.column;

 

if (e.column.id == 4)

$gridService.sort($scope.gridName, e.column, $scope.sorting, comparer);

else

$gridService.sort($scope.gridName, e.column, $scope.sorting);

}

}

<!DOCTYPE html>

<html>

<head>

<link rel="stylesheet" href="css/integralui.css" />

<link rel="stylesheet" href="css/integralui.treegrid.css" />

<link rel="stylesheet" href="css/themes/theme-flat-blue.css" />

<script type="text/javascript" src="external/angular.min.js"></script>

<script type="text/javascript" src="js/angular.integralui.min.js"></script>

<script type="text/javascript" src="js/angular.integralui.lists.min.js"></script>

<script type="text/javascript" src="js/angular.integralui.treegrid.min.js"></script>

</head>

<body>

<div ng-app="appModule" ng-controller="appCtrl">

<iui-treegrid name="{{gridName}}" columns="columns" rows="rows" show-footer="false" grid-lines="gridLines" allow-cell-focus="false" column-click="onColumnClick(e)" sorting="sorting"></iui-treegrid>

</div>

</body>

</html>

As it is shown in above code, whenever a column is clicked sort order is changed and a sort operations will start.

Custom Sort Operation

In case of 3rd column, we are using a comparer function which will sort rows based on custom data. Because in this column cells display dates, there is no built-in sorting which can sort date objects. In this case, we are going to create a custom sort operation by simply creating a comparer function and apply it to the sort method as an argument.

// A call to sort method in Grid directive with custom sorting function

$gridService.sort($scope.gridName, e.column, $scope.sorting, comparer);

 

// Returns the cell which belongs to sorting column

var getCellValue = function(row){

var cellValue = null;

 

if (sortColumn && row.cells){

for (var j = 0; j < row.cells.length; j++){

if (row.cells[j].cid == sortColumn.id){

cellValue = row.cells[j].value;

break;

}

}

}

 

return cellValue;

}

 

// Custom sort function for sorting rows in AngularJS Grid

var comparer = function(firstRow, secondRow){

var x = getCellValue(firstRow);

var y = getCellValue(secondRow);

 

x = x ? x.valueOf() : null;

y = y ? y.valueOf() : null;

 

switch ($scope.sorting){

case 'ascending':

if (x < y)

return -1;

else if (x > y)

return 1;

break;

 

case 'descending':

if (x > y)

return -1;

else if (x < y)

return 1;

break;

 

default:

return 0;

}

}

Because each row can have different number of cells, in order to locate the correct cells that belong to sorting column, we are using the getCellValue function (see above code).

Comparer function simply extracts the cell value and uses it in comparison with other cell values. Because in our example, the cell value is a Date object, at first we are converting this value to a numeric format by calling the valueOf method. In this way, all rows will be sorted in correct order, that is in ascending or descending order.

If some cell doesn't have a value set, then it will be appear on top in ascending order, or at bottom in descending order. Therefore, it is a good practice to have all cells with their value set, prior sorting takes place.

In above demo, whenever a column is clicked, all rows will reorder based on corresponding cell text or value. In order to change the sort order, a column needs to be clicked twice.

The complete sample code is available as part of the IntegralUI Studio for Web product package.

Did you Like this Article?


Enter your e-mail address below and you will receive latest articles as well as news on upcoming events and special offers.