Introduction
The module provides your application with loading overlays to indicate async operations. It is designed to reduce code duplication in controllers and views of your angular application.
Inspired by angular-growl-2
Options
The module provides 2 levels of configuration:
- Global configuration level
- Directive configuration level
Global configuration
Global configuration is applied to all directives by default. It provides the following options:
angular.module('app', [
'bsLoadingOverlay'
]).run(function (bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
delay: 0, // Minimal delay to hide loading overlay in ms.
activeClass: undefined, // Class that is added to the element where bs-loading-overlay is applied when the overlay is active.
templateUrl: undefined // Template url for overlay element. If not specified - no overlay element is created.
templateOptions: undefined // Options that are passed to overlay template (specified by templateUrl option above).
});
});
Directive configuration
Directive configuration overrides global configuration and provides the following options:
- bs-loading-overlay-reference-id
- Reference id for the overlay. When it is used in start, wrap or createHandler options - only this overlay is activated. undefined by default.
- bs-loading-overlay-active-class
- Class that is added to the current div when overlay is activated. empty by default.
- bs-loading-overlay-template-url
- Template url for the element created inside this div when the overlay is activated.
- bs-loading-overlay-template-options
- Options that are passed to overlay template rendering scope. Currently used to for integration with Spin.js. See angular-loading-overlay-spinjs.
Examples
Global
If reference id is not passed to start function - then all loaders which don't have specified reference id are triggered.
app.controller('GlobalController', function($scope, bsLoadingOverlayService) {
$scope.showOverlay = function() {
bsLoadingOverlayService.start();
};
$scope.hideOverlay = function() {
bsLoadingOverlayService.stop();
}
});
<div ng-app="app-global">
<div ng-controller="GlobalController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<button class="btn btn-primary" ng-click="hideOverlay()">Hide overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-global', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
With reference
If reference id is passed to start function - then only overlays with specified ids are triggered.
app.controller('WithReferenceController', function($scope, bsLoadingOverlayService) {
$scope.showOverlay = function(referenceId) {
bsLoadingOverlayService.start({
referenceId: referenceId
});
};
$scope.hideOverlay = function(referenceId) {
bsLoadingOverlayService.stop({
referenceId: referenceId
});
}
});
<div ng-app="app-with-reference">
<div ng-controller="WithReferenceController">
<button class="btn btn-primary" ng-click="showOverlay('first')">Show overlay first</button>
<button class="btn btn-primary" ng-click="hideOverlay('first')">Hide overlay first</button>
<button class="btn btn-primary" ng-click="showOverlay('second')">Show overlay second</button>
<button class="btn btn-primary" ng-click="hideOverlay('second')">Hide overlay second</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-reference-id="first"
>
Some content here
</div>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-reference-id="second"
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-with-reference', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Or it can be passed with directive name attribute
app.controller('WithReferenceInNameAttributeController', function($scope, bsLoadingOverlayService) {
$scope.showOverlay = function(referenceId) {
bsLoadingOverlayService.start({
referenceId: referenceId
});
};
$scope.hideOverlay = function(referenceId) {
bsLoadingOverlayService.stop({
referenceId: referenceId
});
}
});
<div ng-app="app-with-reference-in-name-attribute">
<div ng-controller="WithReferenceInNameAttributeController">
<button class="btn btn-primary" ng-click="showOverlay('first-in-name')">Show overlay first</button>
<button class="btn btn-primary" ng-click="hideOverlay('first-in-name')">Hide overlay first</button>
<button class="btn btn-primary" ng-click="showOverlay('second-in-name')">Show overlay second</button>
<button class="btn btn-primary" ng-click="hideOverlay('second-in-name')">Hide overlay second</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay="first-in-name"
>
Some content here
</div>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay="second-in-name"
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-with-reference-in-name-attribute', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Class
If templateUrl is not specified in global config and in start option and in directive attributes - then no overlay element is created.
On the other hand you can pass active class to directive or start function. In this case the class is added directly to the element where overlay directive is applied.
app.controller('ClassController', function($scope, bsLoadingOverlayService) {
$scope.showOverlay = function() {
bsLoadingOverlayService.start();
};
$scope.hideOverlay = function() {
bsLoadingOverlayService.stop();
}
});
<div ng-app="app-class">
<div ng-controller="ClassController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<button class="btn btn-primary" ng-click="hideOverlay()">Hide overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-active-class="loading-overlay--active"
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-class', [
'bsLoadingOverlay',
'ui.bootstrap'
]);
Hide with delay
To reduce flickering of loading overlay on possibly fast async actions you can add minimal delay to hide overlay.
app.controller('DelayController', function($scope, bsLoadingOverlayService) {
$scope.showOverlay = function() {
bsLoadingOverlayService.start();
};
$scope.hideOverlay = function() {
bsLoadingOverlayService.stop();
}
});
<div ng-app="app-delay">
<div ng-controller="DelayController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<button class="btn btn-primary" ng-click="hideOverlay()">Hide overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-delay="3000"
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-delay', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Handler
To reduce duplication you can create preconfigured handler for your overlay. Then the overlay can be started with simple function call, without options.
app.controller('HandlerController', function($scope, bsLoadingOverlayService) {
var overlayHandler = bsLoadingOverlayService.createHandler({
referenceId: 'handler-overlay'
});
$scope.showOverlay = function() {
overlayHandler.start();
};
$scope.hideOverlay = function() {
overlayHandler.stop();
}
});
<div ng-app="app-handler">
<div ng-controller="HandlerController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<button class="btn btn-primary" ng-click="hideOverlay()">Hide overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-reference-id="handler-overlay"
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-handler', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Wrapper
You can wrap any promise with `wrap` function and then the overlay start function will be called right after the wrap call and stop function will be called on promese resolved or rejected. A promise can also be wrapped with handler (`handler.wrap(somePromiseHere)`).
app.controller('WrapperController', function($scope, $timeout, bsLoadingOverlayService) {
$scope.showOverlay = function() {
bsLoadingOverlayService.wrap({}, $timeout(angular.noop, 5000));
}
});
<div ng-app="app-wrapper">
<div ng-controller="WrapperController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-wrapper', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Wrapper of function returning promise
The same as above, except that you also can wrap a function that returns a promise.
app.controller('WrapperFunctionController', function($scope, $timeout, bsLoadingOverlayService) {
$scope.showOverlay = function() {
bsLoadingOverlayService.wrap({},
function() {
return $timeout(angular.noop, 5000);
});
}
});
<div ng-app="app-wrapper-function">
<div ng-controller="WrapperFunctionController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-wrapper-function', [
'bsLoadingOverlay',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Examples of integration with Spin.js Spin.js
Global
To use default Spin.js integration with default options:
-
Install angular-loading-overlay-spinjs package.
npm install -S angular-loading-overlay-spinjs
-
Add
node_modules/angular-loading-overlay-spinjs/dist/angular-loading-overlay-spinjs.js
script to your page -
Add
bsLoadingOverlaySpinJs
dependency to your app module -
Set global option
templateUrl
tobsLoadingOverlaySpinJs
in your app module run block
app.controller('GlobalSpinjsController', function($scope, bsLoadingOverlayService) {
$scope.showOverlay = function() {
bsLoadingOverlayService.start();
};
$scope.hideOverlay = function() {
bsLoadingOverlayService.stop();
}
});
<div ng-app="app-global-spinjs">
<div ng-controller="GlobalSpinjsController">
<button class="btn btn-primary" ng-click="showOverlay()">Show overlay</button>
<button class="btn btn-primary" ng-click="hideOverlay()">Hide overlay</button>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
>
Some content here
</div>
</div>
</div>
var app = angular.module('app-global-spinjs', [
'bsLoadingOverlay',
'bsLoadingOverlaySpinJs',
'ui.bootstrap'
]).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'bsLoadingOverlaySpinJs'
});
});
With options
You can customize the spinner with options from Spin.js site,
providing options to bs-loading-overlay-template-options
attribute.
With global options
Also you can specify Spin.js options globally in your app module run block.
Examples of integration with $http service
To use default Spin.js integration with default options:
-
Install angular-loading-overlay-http-interceptor package.
npm install -S angular-loading-overlay-http-interceptor
-
Add
node_modules/angular-loading-overlay-http-interceptor/dist/angular-loading-overlay-http-interceptor.js
script to your page -
Add
bsLoadingOverlayHttpInterceptor
dependency to your app module - Add interceptor like in the code below.
app.controller('HttpIntegrationController', function($scope, $http, $sce, bsLoadingOverlayService) {
$scope.result = $sce.trustAsHtml('Fetch result here');
$scope.fetchRandomText = function() {
$http.get('http://hipsterjesus.com/api/')
.success(function(data) {
$scope.result = $sce.trustAsHtml(data.text);
})
.error(function() {
$scope.result = $sce.trustAsHtml('Can not get the article');
});
};
});
<div ng-app="app-http-integration">
<div ng-controller="HttpIntegrationController">
<style>
.fetch-random-result {
overflow: auto;
height: 300px;
margin-top: 1em;
}
</style>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-delay="3000"
>
Fetch random text: <button ng-click="fetchRandomText()">Fetch</button>
<div class="fetch-random-result">
<p ng-bind-html="result"></p>
</div>
</div>
</div>
</div>
var app = angular.module('app-http-integration', [
'bsLoadingOverlay',
'bsLoadingOverlayHttpInterceptor',
'ui.bootstrap'
])
.factory('allHttpInterceptor', function(bsLoadingOverlayHttpInterceptorFactoryFactory) {
return bsLoadingOverlayHttpInterceptorFactoryFactory();
})
.config(function($httpProvider) {
$httpProvider.interceptors.push('allHttpInterceptor');
}).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
With reference id
You can provide referenceId option to interceptor factory.
app.controller('HttpIntegrationWithReferenceIdController', function($scope, $http, $sce, bsLoadingOverlayService) {
$scope.result = $sce.trustAsHtml('Fetch result here');
$scope.fetchRandomText = function() {
$http.get('http://hipsterjesus.com/api/')
.success(function(data) {
$scope.result = $sce.trustAsHtml(data.text);
})
.error(function() {
$scope.result = $sce.trustAsHtml('Can not get the article');
});
};
});
<div ng-app="app-http-integration-with-reference-id">
<div ng-controller="HttpIntegrationWithReferenceIdController">
<style>
.fetch-random-result {
overflow: auto;
height: 300px;
margin-top: 1em;
}
</style>
<div
class="well well-lg bs-loading-container"
bs-loading-overlay
bs-loading-overlay-reference-id="all-ajax-spinner"
bs-loading-overlay-delay="3000"
>
Fetch random text: <button ng-click="fetchRandomText()">Fetch</button>
<div class="fetch-random-result">
<p ng-bind-html="result"></p>
</div>
</div>
</div>
</div>
var app = angular.module('app-http-integration-with-reference-id', [
'bsLoadingOverlay',
'bsLoadingOverlayHttpInterceptor',
'ui.bootstrap'
])
.factory('allHttpInterceptor', function(bsLoadingOverlayHttpInterceptorFactoryFactory) {
return bsLoadingOverlayHttpInterceptorFactoryFactory({
referenceId: 'all-ajax-spinner'
});
})
.config(function($httpProvider) {
$httpProvider.interceptors.push('allHttpInterceptor');
}).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
With matchers
It is also possible to provide requests matcher to interceptors which allows to show spinners for particular requests.
{{randomUser.name.first}} {{randomUser.name.last}}
app.controller('HttpIntegrationWithReferenceIdAndMatchersController', function($scope, $http, $sce, bsLoadingOverlayService) {
$scope.randomText = $sce.trustAsHtml('Fetch result here');
$scope.randomUser = undefined;
$scope.fetchRandomText = function() {
$http.get('http://hipsterjesus.com/api/')
.success(function(data) {
$scope.randomText = $sce.trustAsHtml(data.text);
})
.error(function() {
$scope.randomText = $sce.trustAsHtml('Can not get the article');
});
};
$scope.fetchRandomUser = function() {
$http.get('https://randomuser.me/api/')
.success(function(data) {
$scope.randomUser = data.results[0];
});
};
});
<div ng-app="app-http-integration-with-reference-id-and-matchers">
<div ng-controller="HttpIntegrationWithReferenceIdAndMatchersController">
<style>
.random-result {
display: flex;
height: 300px;
margin-top: 1em;
}
.random-result__text, .random-result__user {
position: relative;
overflow: auto;
border: 2px dashed #C00;
flex: 1;
margin: 1em;
padding: 1em;
text-align: center;
}
.user__photo {
width: 150px;
height: 150px;
border-radius: 50%;
margin: 20px;
}
.user__name {
font-size: 2em;
text-align: center;
}
</style>
<div
class="well well-lg bs-loading-container"
>
<button ng-click="fetchRandomText()">Fetch random text</button>
<button ng-click="fetchRandomUser()">Fetch random user</button>
<div class="random-result">
<div
class="random-result__text"
bs-loading-overlay
bs-loading-overlay-reference-id="random-text-spinner"
bs-loading-overlay-delay="3000"
>
<p ng-bind-html="randomText"></p>
</div>
<div
class="random-result__user user"
bs-loading-overlay
bs-loading-overlay-reference-id="random-user-spinner"
bs-loading-overlay-delay="3000"
>
<div ng-if="randomUser">
<img ng-src="{{randomUser.picture.large}}" alt="" class="user__photo" />
<p class="user__name">
{{randomUser.name.first}} {{randomUser.name.last}}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
var app = angular.module('app-http-integration-with-reference-id-and-matchers', [
'bsLoadingOverlay',
'bsLoadingOverlayHttpInterceptor',
'ui.bootstrap'
])
.factory('randomTextInterceptor', function(bsLoadingOverlayHttpInterceptorFactoryFactory) {
return bsLoadingOverlayHttpInterceptorFactoryFactory({
referenceId: 'random-text-spinner',
requestsMatcher: function (requestConfig) {
return requestConfig.url.indexOf('hipsterjesus') !== -1;
}
});
})
.factory('randomUserInterceptor', function(bsLoadingOverlayHttpInterceptorFactoryFactory) {
return bsLoadingOverlayHttpInterceptorFactoryFactory({
referenceId: 'random-user-spinner',
requestsMatcher: function (requestConfig) {
return requestConfig.url.indexOf('randomuser') !== -1;
}
});
})
.config(function($httpProvider) {
$httpProvider.interceptors.push('randomTextInterceptor');
$httpProvider.interceptors.push('randomUserInterceptor');
}).run(function(bsLoadingOverlayService) {
bsLoadingOverlayService.setGlobalConfig({
templateUrl: 'loading-overlay-template.html'
});
});
Changelog
- 1.1.0 - Template options and intergration with Spin.js.
- 1.0.0 - Transition to typescript. Wrap arguments change.
- 0.3.1 - Fix for version in package.json.
- 0.3.0 - Fix for version according to semver. Fixes for package.json.
- 0.2.1 - Ability to pass reference id with directory name attribute.
- 0.2.0 - Glowl-like API and documentation.