angular-deferred-bootstrap
![Gitter](https://badges.gitter.im/Join Chat.svg)
Initialize your AngularJS app with constants loaded from the back-end.
This component provides a global resolve function for your app. It works similar to the resolve functions you may know from ngRoute or ui-router: You define what needs to be loaded from the back-end before your application can be started and the deferred bootstrapper takes care of loading the data and bootstrapping the application.
- Install
- Usage
- Loading and error indicators
- Advanced usage
- Attach constants to specific modules
- Custom injector modules
- Bootstrap Config and StrictDi
- Testing
- License
Install
Bower
bower install --save angular-deferred-bootstrap
npm
npm install angular-deferred-bootstrap
jspm
jspm install angular-deferred-bootstrap
Usage
Instead of using the ng-app
directive or angular.bootstrap()
, use the deferredBootstrapper
to initialize your app:
deferredBootstrapper.bootstrap({
element: document.body,
module: 'MyApp',
resolve: {
APP_CONFIG: ['$http', function ($http) {
return $http.get('/api/demo-config');
}]
}
});
This will make the response of your $http
call available as a constant to your AngularJS app. This means you can now use dependency injection to access the APP_CONFIG
wherever you need it in your app (even in config()
blocks!).
angular.module('MyApp', [])
.config(function (APP_CONFIG) {
console.log('APP_CONFIG is: ' + JSON.stringify(APP_CONFIG));
})
Loading and error indicators
To make it possible to conditionally show a loading indicator or an error message when the initialization fails, the following CSS classes are set on the HTML body:
- deferred-bootstrap-loading while the data is loading
- deferred-bootstrap-error if an error occurs in a resolve function and the app can not be bootstrapped
Have a look at the demo pages to see this in action.
Advanced usage
You can have multiple constants resolved for your app and you can do in the resolve function whatever is necessary before the app is started. The only constraint is, that the function has to return a promise.
To handle exceptions when the promises are resolved, you can add an onError
function to the configuration object.
Example:
deferredBootstrapper.bootstrap({
element: document.body,
module: 'MyApp',
resolve: {
APP_CONFIG: ['$http', function ($http) {
return $http.get('/api/demo-config');
}],
OTHER_CONSTANT: ['$http', '$q', '$timeout', function ($http, $q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('MyConstant');
}, 2000);
return deferred.promise;
}]
},
onError: function (error) {
alert('Could not bootstrap, error: ' + error);
}
});
Attach constants to specific modules
By default, any constants specified in the resolve
object will be attached to the module specified in the module
option. If you have a need to attach constants to different modules then this can be achieved by using moduleResolves
:
window.deferredBootstrapper.bootstrap({
element: document.body,
module: 'myApp',
moduleResolves: [
{
module: 'myApp.settings',
resolve: {
CONSTANT_ONE: ['$http', function ($http) {
return $http.get();
}],
CONSTANT_TWO: ['$http', function ($http) {
return $http.get();
}]
}
},
{
module: 'myApp.moreSettings',
resolve: {
CONSTANT_THREE: ['$http', function ($http) {
return $http.get();
}]
}
}
]
})
In the above example, CONSTANT_ONE
and CONSTANT_TWO
will be added to the 'myApp.settings'
module and CONSTANT_THREE
will be added to the 'myApp.moreSettings'
module. There are no limits on how many moduleResolve
objects you create and also no limit on the number of constants per moduleResolve
Note that only resolve
or moduleResolves
can be used - using both in the same configuration will throw an exception
Custom injector modules
By default, the injector that calls your resolve functions only provides the services from the AngularJS core module ng
. If you have a use case where you want to use one of your existing services to get configuration at bootstrap time, you can specify which modules should be made available and inject services from those modules in the resolve function. An example is below:
deferredBootstrapper.bootstrap({
element: document.body,
module: 'myApp',
injectorModules: 'myApp.settings',
resolve: {
SETTINGS: ['SettingsService', function (SettingsService) {
return SettingsService.get('/settings');
}]
}
});
The injectorModules
option can also take an array of modules. If you have multiple services spread across different modules you can also inject them:
deferredBootstrapper.bootstrap({
element: document.body,
module: 'myApp',
injectorModules: ['myApp.settings', 'myApp.foo']
resolve: {
SETTINGS: ['SettingsService', function (SettingsService) {
return SettingsService.get('/settings');
}],
FOO: ['FooService', function (FooService) {
return FooService.get('/foo');
}]
}
});
Note that the services which are injected in your resolve functions will be instantiated again when the actual app starts. This means you can not save any state in your services in the resolve functions.
Bootstrap Config and StrictDi
To set the AngularJS strictDi
mode, or any future angular.boostrap
config parameters, pass in an optional config object called bootstrapConfig
:
deferredBootstrapper.bootstrap({
element: document.body,
module: 'MyApp',
bootstrapConfig: {
strictDi: true
},
resolve: {
APP_CONFIG: ['$http', function ($http) {
return $http.get('/api/demo-config');
}]
}
});
Testing
Since the constants that deferredBootstrapper adds to your applications module are not available in your unit tests, it makes sense to provide them in a global beforeEach():
beforeEach(function () {
module(function ($provide) {
$provide.constant('APP_CONFIG', { someUrl: '/dummyValue' });
});
});
License
MIT © Philipp Denzler