Opcjonalne zależności w AngularJS

Próbuję zaimplementować kontroler w AngularJS, który jest używany na wielu stronach. Korzysta z niektórych usług. Niektóre z nich są ładowane na wszystkich stronach, niektóre-nie. Chodzi mi o to, że jest on zdefiniowany w różnych plikach, a te pliki są ładowane niezależnie. Ale jeśli nie Ładuję tych usług na wszystkich stronach, mam błąd:

Error: Unknown provider: firstOtionalServiceProvider <- firstOtionalService

Więc muszę załadować Skrypty na wszystkie strony. Czy mogę zadeklarować zależność jako opcjonalną w Angular? Np.:

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

}]);
Author: T J, 2013-08-31

5 answers

Nie, Angular nie obsługuje jeszcze opcjonalnych zależności po wyjęciu z pudełka. Lepiej umieść wszystkie zależności w module i załaduj go jako jeden plik Javascript. Jeśli potrzebujesz innego zestawu zależności-rozważ utworzenie innego modułu w innym JS i przeniesienie wszystkich wspólnych zależności do wspólnego JS.

Jednak opisane zachowanie można osiągnąć za pomocą $injector serwis . Po prostu wstrzykujesz $injector zamiast wszystkich zależności do kontrolera i wyciągasz zależności z niego ręcznie, sprawdzając, czy istnieją. To jest to:

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

Zobacz to na żywo w ten plunk ! Spróbuj grać z tagami <script> i uważaj na wyjście konsoli.

P. S. i, jak powiedział @problematyczny, możesz użyć $injector.has(), zaczynając od AngularJS 1.1.5.

 50
Author: madhead,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-30 22:03:02

Najwyraźniej nie używa automatycznego wtrysku. Można jednak wstrzyknąć wtryskiwacz i sprawdzić, czy usługa jest wykonywana:

myApp.controller('MyController', [
    '$scope', '$injector', 'firstRequiredService', 'secondRequiredService', 
    function ($scope, $injector, firstRequiredService, secondRequiredService) {
        if ($injector.has('firstOptionalService')) {
            var firstOptionalService = $injector.get('firstOptionalService');
        }
    }
]);
 59
Author: Problematic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-30 20:28:10

Prawdopodobnie zgodziłbym się z sugestią @Proplematic, aby użyć $injector. Jest jednak inne rozwiązanie, które przychodzi mi do głowy: zarejestruj wszystkie usługi z ich domyślnymi wartościami (na przykładnull) w pliku bootstrap. Po załadowaniu dodatkowych plików późniejsze definicje zastąpią domyślne definicje, tworząc w pewnym stopniu pożądany efekt.

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

 13
Author: Buu Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-30 22:12:20

Tak to rozwiązałem:

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');
    }
});
 9
Author: Kenneth Lynne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-27 12:28:27

Spróbuj w ten sposób..

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

'requires' jest tablicą modułów zależności.

 5
Author: simbu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-27 12:41:33