A Pagination service with AngularJS and Bootstrap CSS

In this post, I propose an implementation of an AngularJS service to handle pagination on injected views (via the angular route service and the ng-view directive).

  1. This pagination service has the advantage to be specific to each controller (via instances creation per controller).
  2. Per page data are loaded and refreshed via asynchronous calls to a back-end service (through angular events), you have not to load the entire data and handle pagination on the client side. This service decouples entirely the pagination service with the back end service as you will see later.

follow this link to view and try it on jsFiddle

The Pagination service

A working implementation of the pagination service might seem like this

var Pagination = function(maxCount, $rootScope) {
    this.maxCount = maxCount;
    this.counter = 1;
    
    this.max = function() {
        return this.maxCount;
    };
    this.current = function() {
        return this.counter;
    };
    this.next = function() {
        if (this.hasNext()) {
            this.counter++;
            $rootScope.broadcast("pagination:next");
        }
    };
    this.previous = function() {
        if (this.hasPrevious()) {
            this.counter--;
            $rootScope.broadcast("pagination:previous");
        }
    };
    this.hasPrevious = function() {
        return this.counter > 1;
    };
    this.hasNext = function() {
        return this.counter < this.maxCount;
    };
};

Each time the service is asked to go forth (next) or back (previous), it notifies all registered listeners for page navigation events via rootScope.$broadcast. This will allow us to bind this events to a Back-end service in order to refresh the data for the new displayed page.

The service has two key parameters:

  • maxCount (constructor parameter) is the total number of data that will be handled. This is generally provided by a Back-end service (count all).
  • counter is the current displayed page number.
Return the service through a factory

Since AngularJS services are singleton per application, in order to make the pagination service controller specific, we have to provide it through a factory like service :

// the Pagination service
angular.module('project.services', [])
   .factory('PaginatonService', function($rootScope) {
     return {
       Pagination: function(maxCount, $rootScope) {
         return new Pagination(maxCount);
       }
     };
});
Injecting the service into the controller

The service is then simply declared and instantiated on each controller that requires pagination feature

// injecting the Pagination service into the application module
var myapp = angular.module('project', ['project.services']);
myapp.controller('Controller1', function ($scope, PaginatonService) {
    // here the max count of 10 can be provided by a Backend service through an API
    $scope.pagination = PaginatonService.Pagination(10);
});
myapp.controller('Controller2', function ($scope, PaginatonService) {
    // here the max count of 20 can be provided by a Backend service through an API
    $scope.pagination = PaginatonService.Pagination(20);
});

View Binding

Once the pagination service is added to the controller scope, the binding with AngularJS is straight forward. Here is an example with the Bootstrap CSS Pagination component:

<ul class="pagination">
   <li class="{{pagination.hasPrevious()?'':'disabled'}}"><a href="" ng-click="pagination.previous()">&laquo;</a></li>
   <li ng-show="pagination.hasPrevious()"><a href="">{{pagination.current() - 1}}</a></li>
   <li ng-hide="pagination.hasPrevious()"><span>&nbsp;</span></li>
   <li class="active"><a href="">{{pagination.current()}}</a></li>
   <li ng-show="pagination.hasNext()"><a href="">{{pagination.current() + 1}}</a></li>
   <li class="{{pagination.hasNext()?'':'disabled'}}"><a href="" ng-click="pagination.next()">&raquo;</a></li>
</ul>

I make use of the ng-show AngularJS directive to hide/show navigation on lower and upper data borders/limits.

References

Solving the “Plugin execution not covered by lifecycle configuration” error in Eclipse

In a recent project, we were using the “xmlbeans-maven-plugin” for XML parsing with the “xmlbeans” goal configured on the plugin. However we get this annoying error message about lifecycle configuration on Eclipse “Plugin execution not covered by lifecycle configuration”!

To fix this, one solution consists of adding an ignore configuration to the pom.xml file that says to eclipse to ignore that goal on validation. I personally don’t like this solution because It pollutes the project pom.xml file with IDE specific stuff; and this solution is specific to the project, i.e. you could have this problem on other projects and you just want to fix once for all.

The other solution, that I personally advise, is to add that same configuration to the lifecycle mappings file of the m2e eclipse plugin:

    1. Open the Eclipse preferences window and open the maven preferences page:

2014-05-14_1135

  1. Open the mapping file with “Open workspace lifecycle mappings metadata” and add the following configuration (actually this configuration is the same as the one that is inserted into the project pom file with the help of the “quick-fix” menu):
<?xml version="1.0" encoding="UTF-8"?>
<lifecycleMappingMetadata>
	<pluginExecutions>
		<pluginExecution>
			<pluginExecutionFilter>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>xmlbeans-maven-plugin</artifactId>
				<versionRange>2.3.3</versionRange>
				<goals>
					<goal>xmlbeans</goal>
				</goals>
			</pluginExecutionFilter>
			<action>
				<ignore />
			</action>
		</pluginExecution>
	</pluginExecutions>
</lifecycleMappingMetadata>

This solution will fix the problem for all the projects in your workspace.

Context

  • Eclispe 3.7
  • Maven 2.x
  • m2e eclispe plugin