How to build a UX-friendly progress indicator with AngularJS
Demonstrates building an animated progress indicator using AngularJS, and follows user experience (UX) recommendations for visibility of system status.
For a more detailed walk through, check out http://www.artermobilize.com/blog/2015/08/18/how-to-build-a-ux-friendly-progress-indicator-with-angularjs/
HTML
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<div class="indicator-overlay">
<div class="fa fa-cog fa-spin fa-2x indicator-animation"></div>
</div>
<div ng-app="MyApp" ng-controller="MyController">
<button ng-click="doAsyncStuff()">Click to do something</button>
</div>
CSS
button {
font-size: 1em;
padding: 0.5em;
}
div.indicator-overlay {
height: 100%;
width: 100%;
position: absolute;
z-index: 1000;
background-color: rgba(200, 200, 200, 0.75);
margin: -1rem;
font-size: 4em;
text-align: center;
display: none;
}
div.indicator-animation {
margin: 0 auto;
width: 100%;
margin-top: 10%;
}
JavaScript
var myApp = angular.module('MyApp', []);
myApp.controller('MyController', function ($scope, $http) {
$scope.doAsyncStuff = function () {
$http.post('/echo/json');
}
});
myApp.factory("busyIndicator", function () {
return {
timeout: null,
delayMilliseconds: 1000,
indicatorIsVisible: false,
show: function () {
if (!this.indicatorIsVisible) {
this.indicatorIsVisible = true;
this.timeout = setTimeout(
function() {
$(".indicator-overlay").show();
},
this.delayMilliseconds);
}
},
hide: function () {
clearTimeout(this.timeout);
this.indicatorIsVisible = false;
setTimeout(
function() {
$(".indicator-overlay").hide();
}, this.delayMilliseconds);
}
}
});
myApp.factory('requestBusyIndicator', ['$q', 'busyIndicator', '$timeout', function ($q, busyIndicator, $timeout) {
var requestIndicator = {
request: function (config) {
busyIndicator.show();
return config;
},
response: function (response) {
//Simulate 3 second response time by deferring the response with a timeout
var deferred = $q.defer();
$timeout(function () {
busyIndicator.hide();
deferred.resolve(response);
}, 1100);
return deferred.promise;
},
requestError: function (rejection) {
busyIndicator.hide();
return $q.reject(rejection);
},
responseError: function (rejection) {
busyIndicator.hide();
return $q.reject(rejection);
}
};
return requestIndicator;
}]);
myApp.config(['$httpProvider',
function ($httpProvider) {
$httpProvider.interceptors.push('requestBusyIndicator');
}]);