Angular js table pagination
Creating a table with ng-repeat is quite simple. Adding a search box to filter results is also easy, but only if you want to use a simple text search. It’s a little more complicated if you want to search for values smaller than the one entered by the user. In our example, we will use…
Creating a table with ng-repeat is quite simple. Adding a search box to filter results is also easy, but only if you want to use a simple text search. It’s a little more complicated if you want to search for values smaller than the one entered by the user.
In our example, we will use the planets of the Solar System. We have a name, an average distance from the Sun in units of “distance from Earth to the Sun” and a mass relative to the mass of the Earth. Thus, both values are equal to 1 for Earth. (Earth is not the center of the system, if anything :).
In the first example, we made a table from the data prescribed in the code and added a text filter to all fields:
examples/angular/angular_table_filter_1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=yes">
<title>Table Filter</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module('TableFilterApp', [])
.controller('TableFilterController', function($scope) {
$scope.planets = [
{
name : 'Mercury',
distance : 0.4,
mass : 0.055
},
{
name : 'Venus',
distance : 0.7,
mass : 0.815
},
{
name : 'Earth',
distance: 1,
mass : 1
},
{
name : 'Mars',
distance : 1.5,
mass : 0.107
},
{
name : 'Ceres',
distance : 2.77,
mass : 0.00015
},
{
name : 'Jupiter',
distance : 5.2,
mass : 318
},
{
name : 'Saturn',
distance : 9.5,
mass : 95
},
{
name : 'Uranus',
distance : 19.6,
mass : 14
},
{
name : 'Neptune',
distance : 30,
mass : 17
},
{
name : 'Pluto',
distance : 39,
mass : 0.00218
},
{
name : 'Charon',
distance : 39,
mass : 0.000254
}
];
});
</script>
</head>
<body ng-app="TableFilterApp" ng-controller="TableFilterController">
<table>
<tr><th>Name</th><th>Average Distance</th><th>Mass</th></tr>
<tr><td><input ng-model="f.name"></td><td><input ng-model="f.distance"></td></td><td><input ng-model="f.mass"></td></tr>
<tr ng-repeat="p in planets | filter:f"><td>{{p.name}}</td><td>{{p.distance}}</td><td>{{p.mass}}</td></tr>
</table>
</body>
</html>
The interesting part of the code lies in these two lines:
examples/angular/angular_table_filter_1.js
<tr><td><input ng-model="f.name"></td><td><input ng-model="f.distance"></td></td><td><input ng-model="f.mass"></td></tr>
<tr ng-repeat="p in planets | filter:f"><td>{{p.name}}</td><td>{{p.distance}}</td><td>{{p.mass}}</td></tr>
The second line is what builds the table. It is the usual ng-repeat string, but the results are filtered based on the contents of the f object. The attributes of this object are linked to the input field in the first row. Each attribute will be filtered according to the field of the original array.
In our case, though, the filter only makes sense for the first column. Since this is a simple text filter, it somehow doesn’t make sense to search for all planets that have a distance value of 7. In other tables, it’s probably more interesting.
Searching for values greater or less than
It’s much more interesting to find all planets whose distance is less than 2. Or where the mass is less than 20.
examples/angular/angular_table_filter_2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=yes">
<title>Table Filter</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module('TableFilterApp', [])
.controller('TableFilterController', function($scope) {
$scope.planets = [
{
name : 'Mercury',
distance : 0.4,
mass : 0.055
},
{
name : 'Venus',
distance : 0.7,
mass : 0.815
},
{
name : 'Earth',
distance: 1,
mass : 1
},
{
name : 'Mars',
distance : 1.5,
mass : 0.107
},
{
name : 'Ceres',
distance : 2.77,
mass : 0.00015
},
{
name : 'Jupiter',
distance : 5.2,
mass : 318
},
{
name : 'Saturn',
distance : 9.5,
mass : 95
},
{
name : 'Uranus',
distance : 19.6,
mass : 14
},
{
name : 'Neptune',
distance : 30,
mass : 17
},
{
name : 'Pluto',
distance : 39,
mass : 0.00218
},
{
name : 'Charon',
distance : 39,
mass : 0.000254
}
];
$scope.f = {};
$scope.filter_by = function(field) {
console.log(field);
console.log($scope.g[field]);
if ($scope.g[field] === '') {
delete $scope.f['__' + field];
return;
}
$scope.f['__' + field] = true;
$scope.planets.forEach(function(v) { v['__' + field] = v[field] < $scope.g[field]; })
}
});
</script>
</head>
<body ng-app="TableFilterApp" ng-controller="TableFilterController">
<table>
<tr><th>Name</th><th>Average Distance</th><th>Mass</th></tr>
<tr><td><input ng-model="f.name"></td><td><input ng-model="g.distance" ng-change="filter_by('distance')"></td><td><input ng-model="g.mass" ng-change="filter_by('mass')"></td></tr>
<tr ng-repeat="p in planets | filter:f"><td>{{p.name}}</td><td>{{p.distance}}</td><td>{{p.mass}}</td></tr>
</table>
</body>
</html>
It’s a lot more complicated than that. I haven’t been able to find a better solution yet, so now every time the user enters a value in either the ‘distance’ or ‘mass’ field, the code will go through all the array values and add an extra key to each object with values true if the object fits the condition, or false if it doesn’t. The extra key is made by adding two underscores ‘__’ before the name of the original key. It is assumed that we are unlikely to encounter data where there will be such keys.
The HTML code has changed only slightly. Instead of binding the input field to an attribute of the filter object, we will bind it to another object (named g) and add a function call using ng-change.
examples/angular/angular_table_filter_2b.js
<tr><td><input ng-model="f.name"></td><td><input ng-model="g.distance" ng-change="filter_by('distance')"></td><td><input ng-model="g.mass" ng-change="filter_by('mass')"></td></tr>
When the user changes a value in one of the two fields, Angular will call the filter_by function. First, we’ll check to see if the input field is empty. If it is, we’ll remove all of our created keys.
If there is a value in the field, we will go through all the objects in the planets array and add the appropriate attribute with a value of true or false. The actual filtering will already be done by AngularJS.
examples/angular/angular_table_filter_2.js
$scope.f = {};
$scope.filter_by = function(field) {
if ($scope.g[field] === '') {
delete $scope.f['__' + field];
return;
}
$scope.f['__' + field] = true;
$scope.planets.forEach(function(v) { v['__' + field] = v[field] < $scope.g[field]; })
}
