My angular app depends on a third-party angular service:
var app = angular.module("ninjaModule", ['angular-google-analytics']);
The app loads up just fine, as long as my ad-blocking plugins are off. However, with ad-blockers on angular throws an $injector:nomod
error, failing to load the whole app.
I'm looking for a way to gracefully handle these errors, and therefore be able to load the app regardless of ad-blockers. If angular-google-analytics won't be there - fine, it's not critical, I can deal with it or set up some fallback. But a situation where the whole app crashes is not an option for me. Any ideas?
To be precise - I don't want to work around ad-blockers, e.g. by renaming my script files. I'd expect an angular try-catch magic trick.
I finally got it working. The solution requires a few hacks, though:
- checking if angular-google-analytics is loaded
- preparing the dependency list (
deps
) for the main module on the fly - using
$injector
instead ofAnalytics
explicitly
Still, I need to configure AnalyticsProvider
, but it should be relatively easy to do with $injector
.
var deps = [];
try {
angular.module("angular-google-analytics"); // this throws if GA script is not loaded
deps.push('angular-google-analytics');
} catch(e){ console.error("GA not available", e); }
angular.module('mainApp', deps)
.run(function($rootScope, $injector) {
try {
Analytics = $injector.get('Analytics');
$rootScope.trackPage = function() {
console.log('Analytics in action!');
Analytics.trackPage();
}
} catch(e) {
$rootScope.trackPage = function(key, label) {
console.log("Fallback in action!")
}
}
})
.controller('MyCtrl', function($rootScope, $scope) {
$scope.message = 'Hello World!';
$rootScope.trackPage();
});
Updated plunker: http://plnkr.co/edit/Zo4RgKOybzhvJQdW2nQZ?p=preview
Since angular-google-analytics
requires a config
block to set the account, your best bet is to separate google analytics reporting into a separate sub-module of your App:
//create separate module for analytics reporting
var reportingModule = angular.module('mainApp.reporting', [
'angular-google-analytics'
])
.config(function(AnalyticsProvider) {
AnalyticsProvider.setAccount('UA-HELLO-GA');
})
.run(function(Analytics) {
console.log('mmm.. analytics is good for you');
});
And then inject this sub-module into your main module asynchronously via the module.requires
array so it runs after the main module has finished bootstrapping:
var mainApp = angular.module('mainApp', [
])
.controller('MyCtrl', function($scope) {
$scope.message = 'Hello World!';
});
//set the dependency after app finished bootstrapping
setTimeout(function() {
angular.module('mainApp').requires.push('myapp.reporting');
}, 1);
This way the main module finishes bootstrapping without having the reporting sub-module errors affecting it.
Here's a forked version of your plunkr: http://plnkr.co/edit/lgNZOz4MZx0FGoCOGRC9
The accepted answer breaks gulp dependency injection so I iterated upon it to come up with a more self contained method (you'll still need to inject this module's script tag manually though if you are relying on gulp-inject
).
You can add the dependency dynamically and you can avoid the use of $injector
completely.
angular.module('app', [
'your',
'regular',
'dependencies'
])
.config(function(...) {
/*your normal code*/
})
.run(function(...) {
/*with no concern for analytics*/
})
//mimicking your answer for equivalence
.controller('MyCtrl', function($rootScope) {
if ($rootScope.Analytics)
$rootScope.Analytics.trackPage();
})
;
//protect against adblockers
try {
//throws if not available
angular.module('angular-google-analytics');
//dynamically add the dependency
angular.module('app').requires.push('angular-google-analytics');
//set it up
angular.module('app')
.config(function (AnalyticsProvider) {
AnalyticsProvider.setAccount('UA-00000000-0');
})
//so we dont need to use $injector
.run(function(Analytics, $rootScope) {
$rootScope.Analytics = Analytics;
})
;
} catch(e) { console.error('GA not available'); }
来源:https://stackoverflow.com/questions/32728753/gracefully-handling-angularjs-error-injectornomod-module-unavailable