Mark Kathmann Mark Kathmann - 5 months ago 39
AngularJS Question

AngularJS orderBy on ng-repeat does nothing

I am working on a small demo AngularJS app for my students, but I keep running into trouble with an orderBy filter on an ng-repeat. I am retrieving JSON data via AJAX from a PHP script. The data gets loaded fine, it's just the ordering that doesn't work.

This is the part of the HTML page I'm concerned with:

<div ng-controller="MemberListController">
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
<hr/>
<button ng-click="predicate=''">Set to unsorted</button>

<table class="table">
<thead>
<tr>
<th>
<button ng-click="order('gender')">Geslacht</button>
<span class="sortorder" ng-show="predicate === 'gender'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<button ng-click="order('first_name')">Voornaam</button>
<span class="sortorder" ng-show="predicate === 'first_name'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<button ng-click="order('last_name')">Achternaam</button>
<span class="sortorder" ng-show="predicate === 'last_name'" ng-class="{reverse:reverse}"></span>
</th>
<th>Geboren</th>
<th>Lid sinds</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="member in members track by member.id | orderBy:predicate:reverse" ng-hide="member.deleted == 1">
<td>{{ member.gender }}</td>
<td>{{ member.first_name }}</td>
<td>{{ member.last_name }}</td>
<td>{{ member.birth_date | date:'dd-MMM-yyyy' }}</td>
<td>{{ member.member_since | date:'dd-MMM-yyyy' }}</td>
</tr>
</tbody>
</table>
</div>


This is my Javascript code:

(function ()
{
// init the module
var app = angular.module('ledenjs', []);

// define the memberlist controller
app.controller('MemberListController', ['$scope', '$http', function ($scope, $http)
{
// define and set the scope properties
$scope.members = [];
$scope.predicate = 'last_name';
$scope.reverse = false;

// define the order method
$scope.order = function (predicate)
{
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
$scope.predicate = predicate;
};

// read the members from the db
$http.get('MY_URL_HERE')
.success(function (response)
{
console.log('Received ' + response.length + ' members.');
$scope.members = response;
})
.error(function ()
{
alert('Could not retrieve members from server.');
});
}]);
})();


The JSON data is generated by a very simple script from a sample table:

$result = mysqli_query($mysqli, "SELECT * FROM ledenjs");
while ($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}
header("Content-Type: application/json");
echo json_encode($data);


A slice of the returned data:

[{"id":"10001","birth_date":"1953-09-02","first_name":"Georgi","last_name":"Facello","gender":"M","member_since":"1986-06-26","deleted":"0"},{"id":"10002","birth_date":"1964-06-02","first_name":"Bezalel","last_name":"Simmel","gender":"F","member_since":"1985-11-21","deleted":"0"},{"id":"10003","birth_date":"1959-12-03","first_name":"Parto","last_name":"Bamford","gender":"M","member_since":"1986-08-28","deleted":"0"},{"id":"10004","birth_date":"1954-05-01","first_name":"Chirstian","last_name":"Koblick","gender":"M","member_since":"1986-12-01","deleted":"0"}]


So...I've looked at the questions on this subject here on SO, I've looked at the AngularJS documentation for OrderBy here (as you can see my code is based on the samples on there), but still my table won't sort.

I know that most of these questions are answered by "orderBy won't work on objects, only on arrays", but my data is an array by the looks of it, and the actual retrieval is working fine, I am seeing the console log line with the correct number of records when I load the page.

This is slowly driving me up the wall...any help would be greatly appreciated.

Mark.

SOLVED: Thanks to Dmitriy Khudorozhkov for pointing out that "track by" and "orderBy" tend to interfere. It does work is you put the "track by" at the end, after all the filters:

<tr ng-repeat="member in members | orderBy:predicate:reverse track by member.id">

Answer
<tr ng-repeat="member in members track by member.id | orderBy:predicate:reverse" ng-hide="member.deleted == 1">

- this line may break in AngularJS prior to version 1.2; try to remove the

track by member.id

part and see if it works.

Update: the real solution for Angular v.1.2 and later is:

ng-repeat="member in members | orderBy:predicate:reverse track by member.id"

- tracking should come after orderBy clause.

Comments