gmeka
gmeka

Reputation: 4289

orderBy multiple fields in Angular

How to sort by using multiple fields at same time in angular? fist by group and then by sub-group for Example

$scope.divisions = [{'group':1,'sub':1}, {'group':2,'sub':10}, {'group':1,'sub':2},{'group':1,'sub':20},{'group':2,'sub':1},
    {'group':2,'sub':11}];

I wanted to display this as

group : Sub-group

1 - 1

1 - 2

1 - 20

2 - 1

2 - 10

2 - 11

<select ng-model="divs" ng-options="(d.group+' - '+d.sub) for d in divisions | orderBy:'group' | orderBy:'sub'" />

Upvotes: 392

Views: 208706

Answers (8)

Andris
Andris

Reputation: 4193

Created Pipe for sorting. Accepts both string and array of strings, sorting by multiple values. Works for Angular (not AngularJS). Supports both sort for string and numbers.

@Pipe({name: 'orderBy'})
export class OrderBy implements PipeTransform {
    transform(array: any[], filter: any): any[] {
        if(typeof filter === 'string') {
            return this.sortAray(array, filter)
        } else {
            for (var i = filter.length -1; i >= 0; i--) {
                array = this.sortAray(array, filter[i]);
            }

            return array;
        }
    }

    private sortAray(array, field) {
        return array.sort((a, b) => {
            if(typeof a[field] !== 'string') {
                a[field] !== b[field] ? a[field] < b[field] ? -1 : 1 : 0
            } else {
                a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0
            }
        });
    }
}

Upvotes: 0

Stokely
Stokely

Reputation: 15759

I wrote this handy piece to sort by multiple columns / properties of an object. With each successive column click, the code stores the last column clicked and adds it to a growing list of clicked column string names, placing them in an array called sortArray. The built-in Angular "orderBy" filter simply reads the sortArray list and orders the columns by the order of column names stored there. So the last clicked column name becomes the primary ordered filter, the previous one clicked the next in precedence, etc. The reverse order affects all columns order at once and toggles ascending/descending for the complete array list set:

<script>
    app.controller('myCtrl', function ($scope) {
        $scope.sortArray = ['name'];
        $scope.sortReverse1 = false;
        $scope.searchProperty1 = '';
        $scope.addSort = function (x) {
            if ($scope.sortArray.indexOf(x) === -1) {
                $scope.sortArray.splice(0,0,x);//add to front
            }
            else {
                $scope.sortArray.splice($scope.sortArray.indexOf(x), 1, x);//remove
                $scope.sortArray.splice(0, 0, x);//add to front again
            }
        };
        $scope.sushi = [
        { name: 'Cali Roll', fish: 'Crab', tastiness: 2 },
        { name: 'Philly', fish: 'Tuna', tastiness: 2 },
        { name: 'Tiger', fish: 'Eel', tastiness: 7 },
        { name: 'Rainbow', fish: 'Variety', tastiness: 6 },
        { name: 'Salmon', fish: 'Misc', tastiness: 2 }
        ];
    });
</script>
<table style="border: 2px solid #000;">
<thead>
    <tr>
        <td><a href="#" ng-click="addSort('name');sortReverse1=!sortReverse1">NAME<span ng-show="sortReverse1==false">&#9660;</span><span ng-show="sortReverse1==true">&#9650;</span></a></td>
        <td><a href="#" ng-click="addSort('fish');sortReverse1=!sortReverse1">FISH<span ng-show="sortReverse1==false">&#9660;</span><span ng-show="sortReverse1==true">&#9650;</span></a></td>
        <td><a href="#" ng-click="addSort('tastiness');sortReverse1=!sortReverse1">TASTINESS<span ng-show="sortReverse1==false">&#9660;</span><span ng-show="sortReverse1==true">&#9650;</span></a></td>
    </tr>
</thead>
<tbody>
    <tr ng-repeat="s in sushi | orderBy:sortArray:sortReverse1 | filter:searchProperty1">
        <td>{{ s.name }}</td>
        <td>{{ s.fish }}</td>
        <td>{{ s.tastiness }}</td>
    </tr>
</tbody>
</table>

Upvotes: 1

Alireza
Alireza

Reputation: 104640

There are 2 ways of doing AngularJs filters, one in the HTML using {{}} and one in actual JS files...

You can solve you problem by using :

{{ Expression | orderBy : expression : reverse}}

if you use it in the HTML or use something like:

$filter('orderBy')(yourArray, yourExpression, reverse)

The reverse is optional at the end, it accepts a boolean and if it's true, it will reverse the Array for you, very handy way to reverse your Array...

Upvotes: 7

Tessy Thomas
Tessy Thomas

Reputation: 1485

Sorting can be done by using 'orderBy' filter in angular.

Two ways: 1. From view 2. From controller

  1. From view

Syntax:

{{array | orderBy : expression : reverse}} 

For example:

 <div ng-repeat="user in users | orderBy : ['name', 'age'] : true">{{user.name}}</div>
  1. From controller

Syntax:

$filter.orderBy(array, expression, reverse);

For example:

$scope.filteredArray = $filter.orderBy($scope.users, ['name', 'age'], true);

Upvotes: 7

Jens Alenius
Jens Alenius

Reputation: 1931

Make sure that the sorting is not to complicated for the end user. I always thought sorting on group and sub group is a little bit complicated to understand. If its a technical end user it might be OK.

Upvotes: -8

Muhammad Raza Dar
Muhammad Raza Dar

Reputation: 521

If you wants to sort on mulitple fields inside controller use this

$filter('orderBy')($scope.property_list, ['firstProp', 'secondProp']);

See also https://docs.angularjs.org/api/ng/filter/orderBy

Upvotes: 50

Thambuleena
Thambuleena

Reputation: 253

<select ng-model="divs" ng-options="(d.group+' - '+d.sub) for d in divisions | orderBy:['group','sub']" />

User array instead of multiple orderBY

Upvotes: 21

Chubby Boy
Chubby Boy

Reputation: 31062

Please see this:

http://jsfiddle.net/JSWorld/Hp4W7/32/

<div ng-repeat="division in divisions | orderBy:['group','sub']">{{division.group}}-{{division.sub}}</div>

Upvotes: 684

Related Questions