我正在尝试在AngularJS中实现一个跨多个页面使用的控制器。它利用了一些服务。其中一些是在所有页面上加载的,有些是 - 不是。我的意思是它在不同的文件中定义,并且这些文件是独立加载的。但如果我没有在所有页面上加载这些服务,我就会收到错误:
Error: Unknown provider: firstOtionalServiceProvider <- firstOtionalService
所以,我需要在所有页面上加载脚本。我可以在Angular中将依赖声明为可选的吗? E.g:
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();
}
}]);
答案 0 :(得分:59)
显然不使用自动注射。但是,您可以注入进样器并检查服务:
myApp.controller('MyController', [
'$scope', '$injector', 'firstRequiredService', 'secondRequiredService',
function ($scope, $injector, firstRequiredService, secondRequiredService) {
if ($injector.has('firstOptionalService')) {
var firstOptionalService = $injector.get('firstOptionalService');
}
}
]);
答案 1 :(得分:53)
不,Angular尚未支持开箱即用的可选依赖项。您最好将所有依赖项放入模块并将其作为一个Javascript文件加载。如果你需要另一组依赖项 - 考虑在另一个JS中创建另一个模块并将所有常见的依赖项放到普通的JS中。
但是,您所描述的行为可以通过$injector
service来实现。您只需将$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');
}
});
在this plunk中查看!尝试使用<script>
标签并观察控制台输出。
P.S。而且,正如@Problematic所说,你可以使用$injector.has()
,从AngularJS 1.1.5开始。
答案 2 :(得分:13)
我可能会选择@ Proplematic建议使用$ injector。但是,我可以想到另一种解决方案:在引导文件中注册所有服务的默认值(例如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
});
答案 3 :(得分:9)
这就是我解决它的方法:
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');
}
});
答案 4 :(得分:5)
试试这种方式..
try {
angular.module('YourModule').requires.push('Optional dependency module');
} catch(e) {
console.log(e)
}
'requires'是一个依赖模块数组。