Progress Indicators with AngularJS and JHipster

In this application, I'm using the Bootstrap Angulr theme (demo). This theme comes with a progress bar that pulsates at the top of the page. It's activated by a uiButterbar directive. This directive shows the bar when there's a ui-router state transition in progress and hides it when it's complete.

.directive('uiButterbar', ['$rootScope', '$anchorScroll', function ($rootScope, $anchorScroll) {
    return {
        restrict: 'AC',
        template: '<span class="bar"></span>',
        link: function (scope, el, attrs) {
            el.addClass('butterbar hide');
            scope.$on('$stateChangeStart', function (event) {
                $anchorScroll();
                el.removeClass('hide').addClass('active');
            });
            scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
                event.targetScope.$watch('$viewContentLoaded', function () {
                    el.addClass('hide').removeClass('active');
                })
            });
        }
    };
}]);

This directive is referenced in the HTML using a <div> tag.

<div ui-butterbar></div>

The CSS for this progress bar uses CSS animations. You can see it here.

When I first started using the Angulr theme, I found I had to pre-load data for a controller to activate the loading bar. For example, this is what this main.controller.js looks like currently.

.controller('MainController', function ($sce, $scope, $state, $stateParams, Principal, Blog, Entry, Tag, ParseLinks, entry) {
    Principal.identity().then(function(account) {
        $scope.account = account;
        $scope.isAuthenticated = Principal.isAuthenticated;
    });

    $scope.showComments = false;
    var defaultTitle = "The JHipster Mini-Book";

    // Get entry if its passed in
    if (entry != null) {
        $scope.entry = entry.data;
        $scope.showComments = true;
        document.title = $scope.entry.title + " | " + defaultTitle;
    } else {
        document.title = defaultTitle;
    }

    $scope.tags = Tag.query();
    $scope.page = 0;

    Blog.get({id: 1}, function(data) {
        $scope.blog = data;
        Entry.query({page: $scope.page, size: 20, handle: data.handle}, function(result, headers) {
            $scope.links = ParseLinks.parse(headers('link'));
            $scope.entrys = result;
        });
    });

    $scope.trustHtml = function (html) {
        return $sce.trustAsHtml(html);
    };
});

To pre-load data with ui-router, you can use resolve in a route. For example, to resolve tags and blog before activating the controller, you could add new keys to the resolve property map in main.js.

resolve: {
    tags: function (Tag) {
        return Tag.query().$promise;
    },
    blog: function (Blog) {
        return Blog.get({id: 1}).$promise;
    }
}

Then you could change main.controller.js to inject these objects.

.controller('MainController', function ($sce, $scope, $state, $stateParams, Principal, Entry, ParseLinks, blog, entry, tags) {
    // same code as above

    $scope.tags = tags
    $scope.page = 0;
    $scope.blog = blog;

    Entry.query({page: $scope.page, size: 20, handle: data.handle}, function(result, headers) {
        $scope.links = ParseLinks.parse(headers('link'));
        $scope.entrys = result;
    });

    $scope.trustHtml = function (html) {
        return $sce.trustAsHtml(html);
    };
});

While I liked this progress bar, I found it had a couple issues: 1) I had to change every JHipster-generated route and controller to pre-load data and 2) it wouldn't work easily with applications not using the Angulr theme. With the books sample application, 21-Points Health, I wasn't using this theme. So I went searching for something better.

It didn't take me long to find Angular Loading Bar. This is a nifty progress bar that works great out of the box. You can install it using Bower:

bower install angular-loading-bar --save

Then provide a reference to it in app.js. That's it!

angular.module('myApp', ['angular-loading-bar'])

It's so easy, I decided to add it to this application as I was writing this blog post. This component is included in the next JHipster release and you can easily add it to your project. See this pull request to see how.

Progress indicators like this are important to let the user know that things are happening in your application. Another nice feature is progress indicators on Save buttons. I recently had to add this to a client's project because we have a bulk update screen that can take a while to save changes. I found a number of progress indicator buttons that looked great for this purpose.

After some more research, I found a Stack Overflow question that led me to Ladda UI for Bootstrap 3. I liked these buttons since they were based on Bootstrap. I found angular-ladda as an easy way to integrate these buttons into an Angular application.

In my client's application, I only wanted to add progress indicators on a couple buttons: login and the aforementioned bulk update screen. I did create a pull request to add it to JHipster. However, we later decided not to include it since adding Angular Loading Bar seemed like enough.

This article showed you how to add a progress indicator to your Angular application. It also showed how you can use angular-ladda to add spinner's to your form buttons. If you've used other progress indicators in your Angular apps, I'd love to hear about them.

Code Syntax Highlighting
I added SyntaxHighlighter to this application to make the code prettier in blog posts like this one. However, I've had intermittent success. Sometimes it formats the code blocks, most of the time it doesn't. I included all the necessary CSS and JS files, then added the following to main.controller.js.

$scope.$on('$viewContentLoaded', function() {
    SyntaxHighlighter.all();
});

← Back to Home All Posts