I have four table headers:
$scope.headers = ["Header1", "Header2", "Header3", "Header4"];
And I want to be able to sort my table by clicking on the header.
So if my table looks like this
H1 | H2 | H3 | H4
A H D etc....
B G C
C F B
D E A
and I click on
H2
my table now looks like this:
H1 | H2 | H3 | H4
D E A etc....
C F B
B G C
A H D
That is, the content of each column never changes, but by clicking on the header I want to order the columns by, the rows will reorder themselves.
The content of my table is created by a database call done with Mojolicious and is returned to the browser with
$scope.results = angular.fromJson(data); // This works for me so far
The rest of the code I have cobbled together looks something like this:
<table class= "table table-striped table-hover">
<th ng-repeat= "header in headers">
<a> {{headers[$index]}} </a>
</th>
<tr ng-repeat "result in results">
<td> {{results.h1}} </td>
<td> {{results.h2}} </td>
<td> {{results.h3}} </td>
<td> {{results.h4}} </td>
</tr>
</table>
How do I order the columns from this point, just by clicking on the header at the top of the table?
I think this working CodePen example that I created will show you exactly how to do what you want.
The template:
<section ng-app="app" ng-controller="MainCtrl">
<span class="label">Ordered By: {{orderByField}}, Reverse Sort: {{reverseSort}}</span><br><br>
<table class="table table-bordered">
<thead>
<tr>
<th>
<a href="#" ng-click="orderByField='firstName'; reverseSort = !reverseSort">
First Name <span ng-show="orderByField == 'firstName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='lastName'; reverseSort = !reverseSort">
Last Name <span ng-show="orderByField == 'lastName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='age'; reverseSort = !reverseSort">
Age <span ng-show="orderByField == 'age'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="emp in data.employees|orderBy:orderByField:reverseSort">
<td>{{emp.firstName}}</td>
<td>{{emp.lastName}}</td>
<td>{{emp.age}}</td>
</tr>
</tbody>
</table>
</section>
The JavaScript code:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.orderByField = 'firstName';
$scope.reverseSort = false;
$scope.data = {
employees: [{
firstName: 'John',
lastName: 'Doe',
age: 30
},{
firstName: 'Frank',
lastName: 'Burns',
age: 54
},{
firstName: 'Sue',
lastName: 'Banter',
age: 21
}]
};
});
Here is a fiddle that can help you to do this with AngularJS
http://jsfiddle.net/patxy/D2FsZ/
<th ng:repeat="(i,th) in head" ng:class="selectedCls(i)" ng:click="changeSorting(i)">
{{th}}
</th>
Then something like this for your data:
<tr ng:repeat="row in body.$orderBy(sort.column, sort.descending)">
<td>{{row.a}}</td>
<td>{{row.b}}</td>
<td>{{row.c}}</td>
</tr>
With such functions in your AngularJS controller:
scope.sort = {
column: 'b',
descending: false
};
scope.selectedCls = function(column) {
return column == scope.sort.column && 'sort-' + scope.sort.descending;
};
scope.changeSorting = function(column) {
var sort = scope.sort;
if (sort.column == column) {
sort.descending = !sort.descending;
} else {
sort.column = column;
sort.descending = false;
}
};
Another way to do this in AngularJS is to use a Grid.
The advantage with grids is that the row sorting behavior you are looking for is included by default.
The functionality is well encapsulated. You don't need to add ng-click attributes, or use scope variables to maintain state:
<body ng-controller="MyCtrl">
<div class="gridStyle" ng-grid="gridOptions"></div>
</body>
You just add the grid options to your controller:
$scope.gridOptions = {
data: 'myData.employees',
columnDefs: [{
field: 'firstName',
displayName: 'First Name'
}, {
field: 'lastName',
displayName: 'Last Name'
}, {
field: 'age',
displayName: 'Age'
}]
};
Full working snippet attached:
var app = angular.module('myApp', ['ngGrid', 'ngAnimate']);
app.controller('MyCtrl', function($scope) {
$scope.myData = {
employees: [{
firstName: 'John',
lastName: 'Doe',
age: 30
}, {
firstName: 'Frank',
lastName: 'Burns',
age: 54
}, {
firstName: 'Sue',
lastName: 'Banter',
age: 21
}]
};
$scope.gridOptions = {
data: 'myData.employees',
columnDefs: [{
field: 'firstName',
displayName: 'First Name'
}, {
field: 'lastName',
displayName: 'Last Name'
}, {
field: 'age',
displayName: 'Age'
}]
};
});
/*style.css*/
.gridStyle {
border: 1px solid rgb(212,212,212);
width: 400px;
height: 200px
}
<!DOCTYPE html>
<html ng-app="myApp">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular-animate.js"></script>
<script type="text/javascript" src="http://angular-ui.github.com/ng-grid/lib/ng-grid.debug.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body ng-controller="MyCtrl">
<div class="gridStyle" ng-grid="gridOptions"></div>
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With