I have an existing application that uses a MapProvider
like so:
mapModule.factory('MapProvider', ['$injector', function($injector) {
return $injector.get('GoogleMapsService');
}]);
This MapProvider is used extensively across the application and is injected into various other controllers and services (rightly or wrongly).
I now need to add a BaiduMapsService
, which I have been able to get working as a test with:
mapModule.factory('MapProvider', ['$injector', function($injector) {
if(true) {
return $injector.get('GoogleMapsService');
} else {
return $injector.get('BaiduMapsService');
}
}]);
And flipping the if
value accordingly. (Both of these services are using a TypeScript interface, so have the same methods). Now, I need to add a $http
call to the API, which will return which map to use, based on the provided data. How can I make my factory asynchronous, without having to change all my MapProvider.someCallHere()
calls to MapProvider.then(m => m.someCallHere())
.
Ideally, when MapProvider
is injected across my application, it will be able to resolve using the async data (only once), and then inject the necessary service afterwards.
Alternatively, is there a way to defer / delay loading Angular at all, until I make an API call and set some global data somewhere?
Thanks.
You can postpone the application bootstrap
(also, don't use ng-app
, do it manually) until you get data from server. I've answered this before on this question but each case has its own specific details.
I usually see a config value being declared on the app before the application gets bootstraped, this is very useful for multi-tenant apps. So that this preference values can be used in the whole app as an injected provider.
For example:
var app = angular.module('app', []);
// retrieve the $http provider
var ngInjector = angular.injector(["ng"]);
var $http = ngInjector.get("$http");
// load config function. Returns a promise.
function loadConfig(){
return $http.get("/config.json").then(function(response) {
// declare the configuration value on your app
app.constant("Config", response.data);
}, function(err) {
console.error("Error loading the application config.", err)
});
}
// Call loadConfig then bootstrap the app
loadConfig().then(function () {
angular.element(document).ready(function() {
angular.bootstrap(document, ["app"]);
});
});
Finally from your factory, you can use the Config
constant to retrieve the preferred map.
mapModule.factory('MapProvider', ['$injector', 'Config', function($injector, Config) {
if(Config.preferedMap == 'GoogleMap') {
return $injector.get('GoogleMapsService');
} else {
return $injector.get('BaiduMapsService');
}
}]);