I\'m trying to implement a controller in AngularJS which is used across multiple pages. It makes use of some services. Some of them are loaded on all pages, some - not. I me
Apparently not using automatic injection. However, you can inject the injector and check for the service:
myApp.controller('MyController', [
'$scope', '$injector', 'firstRequiredService', 'secondRequiredService',
function ($scope, $injector, firstRequiredService, secondRequiredService) {
if ($injector.has('firstOptionalService')) {
var firstOptionalService = $injector.get('firstOptionalService');
}
}
]);
No, Angular does not yet support optional dependencies out of the box. You'd better put all your dependencies into a module and load it as one Javascript file. If you need another set of dependencies - consider creating another module in another JS and putting all common dependencies to common JS.
However, behavior you've described can be achieved with $injector service. You simply inject $injector
instead of all your dependencies to a controller and pull dependencies from it manually, checking if they exist. That's it:
index.html:
<!DOCTYPE html>
<html data-ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<script src="app.js"></script>
<script src="1.js"></script>
<script src="2.js"></script>
<title>1</title>
</head>
<body data-ng-controller="DemoController">
</body>
</html>
app.js:
var myApp = angular.module('myApp', []);
myApp.service('commonService', function(){
this.action = function(){
console.log('Common service is loaded');
}
});
myApp.controller('DemoController', ['$scope', '$injector', function($scope, $injector){
var common;
var first;
var second;
try{
common = $injector.get('commonService');
console.log('Injector has common service!');
}catch(e){
console.log('Injector does not have common service!');
}
try{
first = $injector.get('firstService');
console.log('Injector has first service!');
}catch(e){
console.log('Injector does not have first service!');
}
try{
second = $injector.get('secondService');
console.log('Injector has second service!');
}catch(e){
console.log('Injector does not have second service!');
}
if(common){
common.action();
}
if(first){
first.action();
}
if(second){
second.action();
}
}]);
1.js:
myApp.service('firstService', function(){
this.action = function(){
console.log('First service is loaded');
}
});
2.js:
myApp.service('secondService', function(){
this.action = function(){
console.log('Second service is loaded');
}
});
See it live in this plunk! Try to play with <script>
tags and watch for console output.
P.S. And, as @Problematic said, you can use $injector.has()
, starting from AngularJS 1.1.5.
I'd probably go with @Proplematic's suggestion of using $injector. However, there is another solution I can think of: register all services with their default values (null
for example) in your bootstrap file. When additional files are loaded, later definitions will override the default definitions, somewhat creating the effect you desire.
var app = angular.module('plunker', []);
app.value("service1", null)
.value("service2", null)
.factory("service1", function() { return "hello"; });
app.controller('MainCtrl', function($scope, service1, service2) {
console.log(service1); // hello
console.log(service2); // null
});
Demo link
Try this way..
try {
angular.module('YourModule').requires.push('Optional dependency module');
} catch(e) {
console.log(e)
}
'requires' is an Array of dependency modules.
This is how i solved it:
var deps = [];
try {
//Check if optionalModule is available
angular.module('app').requires.push('optionalModule');
deps.push('optionalModule');
} catch(e){
console.log("Warn: module optionalModule not found. Maybe it's normal");
}
angular.module('app', deps).factory('stuff', function($injector) {
var optionalService;
if($injector.has('optionalService')) {
optionalService = $injector.get('optionalService');
} else {
console.log('No waffles for you, dear sir');
}
});