48

我試圖在多個頁面中使用的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(); 
    } 

}]); 

回答

50

不,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說,你可以使用從AngularJS 1.1.5開始的$injector.has()

+0

謝謝!正是我需要的。我正在使用最新的Angular,所以請使用'has'! – molaccha

56

顯然不使用自動注射。但是,您可以注射進樣器並檢查服務:

myApp.controller('MyController', [ 
    '$scope', '$injector', 'firstRequiredService', 'secondRequiredService', 
    function ($scope, $injector, firstRequiredService, secondRequiredService) { 
     if ($injector.has('firstOptionalService')) { 
      var firstOptionalService = $injector.get('firstOptionalService'); 
     } 
    } 
]); 
+0

酷!我想他們backport'$ injector.has'到1.0.7! – madhead

+3

不錯!這是從我的角度來看的正確答案 – Gabriel

+2

我喜歡@ madhead的這個答案,因爲它使用'$ injector.has'而不是'try' /'catch' –

13

我可能會用@Proplematic的建議使用$注入器。但是,我可以想到另一種解決方案:將所有服務的默認值(例如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 
}); 

Demo link

+0

這是哈克,但工程。我使用它的地方有多條共享控制器的路由,但只有少數需要解決:注入的屬性。 – httpete

+0

這是帶有可選參數的項目的最佳答案。 – sean

+0

這正是我想要的!謝謝! 我需要使用與模態控制器相同的控制器,也需要使用ng控制器。而對於模態控制器,我需要額外的解析器。 –

5

嘗試這樣..

try { 
    angular.module('YourModule').requires.push('Optional dependency module'); 
} catch(e) { 
    console.log(e) 
} 

'需要' 是的依賴性模塊的陣列。

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'); 
    } 
});