Optional dependencies in AngularJS Optional dependencies in AngularJS angularjs angularjs

Optional dependencies in AngularJS


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