AngularJS中的可选依赖项
我正在尝试在AngularJS中实现一个跨多个页面使用的控制器。 它利用一些服务。 其中一些在所有页面上加载,一些则不在。 我的意思是它是在不同的文件中定义的,并且这些文件是独立加载的。 但是,如果我不加载所有页面上的这些服务,我得到的错误:
Error: Unknown provider: firstOtionalServiceProvider <- firstOtionalService
所以,我需要在所有页面上加载脚本。 我可以在Angular中声明依赖项作为可选项吗? 例如:
myApp.controller('MyController', ['$scope', 'firstRequiredService', 'secondRequiredService', 'optional:firstOptionalService', 'optional:secondOptionalService', function($scope, firstRequiredService, secondRequiredService, firstOptionalService, secondOptionalSerivce){ // No need to check, as firstRequiredService must not be null firstRequiredService.alwaysDefined(); // If the dependency is not resolved i want Angular to set null as argument and check if (firstOptionalService) { firstOptionalService.mayBeUndefinedSoCheckNull(); } }]);
不,Angular目前还不支持可选的依赖关系。 你最好把所有的依赖关系放到一个模块中,并把它作为一个Javascript文件加载。 如果你需要另一组依赖 – 考虑在另一个JS中创build另一个模块,并将所有常见的依赖关系放到常见的JS中。
但是,您所描述的行为可以通过$injector
服务来实现。 您只需将$injector
而不是所有的依赖项注入到控制器,并手动从其中取出依赖项,检查它们是否存在。 而已:
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'); } });
看到它活在这个庞然大物 ! 尝试玩<script>
标签,并观看控制台输出。
PS和@Problematic说,你可以使用$injector.has()
,从AngularJS 1.1.5开始。
显然不使用自动注入。 但是,您可以注射进样器并检查服务:
myApp.controller('MyController', [ '$scope', '$injector', 'firstRequiredService', 'secondRequiredService', function ($scope, $injector, firstRequiredService, secondRequiredService) { if ($injector.has('firstOptionalService')) { var firstOptionalService = $injector.get('firstOptionalService'); } } ]);
我可能会与@ Proplematic的build议使用$注入器。 但是,我可以想到另一个解决scheme:在引导文件中将所有服务的默认值(例如null
)注册。 当加载额外的文件时,以后的定义将覆盖默认的定义,有点创造你想要的效果。
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 });
演示链接
这是我解决它的方法:
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'); } });
试试这个方法..
try { angular.module('YourModule').requires.push('Optional dependency module'); } catch(e) { console.log(e) }
'require'是一个依赖模块数组。