48

Ich versuche, einen Controller in AngularJS zu implementieren, der über mehrere Seiten hinweg verwendet wird. Es nutzt einige Dienste. Einige von ihnen sind auf allen Seiten geladen, andere nicht. Ich meine, es ist in verschiedenen Dateien definiert, und diese Dateien werden unabhängig voneinander geladen. Aber wenn ich diese Dienste nicht auf allen Seiten lade, habe ich Fehler:Optionale Abhängigkeiten in AngularJS

Also muss ich Skripte auf allen Seiten laden. Kann ich die Abhängigkeit in Angular als optional deklarieren? ZB:

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

}]); 

Antwort

50

Nein, Angular unterstützt optionale Abhängigkeiten nicht sofort aus der Box. Sie sollten alle Ihre Abhängigkeiten in ein Modul einfügen und es als eine Javascript-Datei laden. Wenn Sie einen weiteren Satz von Abhängigkeiten benötigen, sollten Sie in Erwägung ziehen, ein anderes Modul in einem anderen JS zu erstellen und alle allgemeinen Abhängigkeiten in ein gemeinsames JS zu setzen. Das von Ihnen beschriebene Verhalten kann mit $injector service erreicht werden. Sie injizieren einfach statt all Ihrer Abhängigkeiten zu einem Controller und ziehen Abhängigkeiten von diesem manuell und prüfen, ob sie existieren. Das ist es:

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

es Siehe Live in this plunk! Versuchen Sie, mit <script> Tags zu spielen und achten Sie auf Konsolenausgabe.

P.S. Und wie @Problematic sagte, können Sie $injector.has() verwenden, beginnend mit AngularJS 1.1.5.

+0

Thank you! Genau das, was ich brauche. Ich benutze das neueste Angular, also benutze 'has'! – molaccha

56

Scheinbar keine automatische Injektion verwenden. Sie können jedoch den Injektor und prüfen Sie für den Dienst injizieren:

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

Cool! Ich will sie backport '$ injector.has' zu 1.0.7! – madhead

+3

Schön! Dies ist die richtige Antwort aus meiner Sicht – Gabriel

+2

Ich mag diese Antwort über @ Madhead's, weil es '$ injector.has' anstelle von' try'/'catch' verwendet –

13

ich wahrscheinlich mit @ Proplematic Vorschlag der Verwendung von $ Injektor gehen würde. Allerdings gibt es eine andere Lösung, die ich mir vorstellen kann: Registrieren Sie alle Dienste mit ihren Standardwerten (null zum Beispiel) in Ihrer Bootstrap-Datei. Wenn zusätzliche Dateien geladen werden, überschreiben spätere Definitionen die Standarddefinitionen und erzeugen so den von Ihnen gewünschten Effekt.

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

Das ist hacky, aber funktioniert. Ich benutze es, wo ich mehrere Routen habe, die einen Controller teilen, aber nur ein paar brauchen eine Lösung: {} Eigenschaft injiziert. – httpete

+0

Dies ist die beste Antwort für mein Projekt mit optionalen Parametern. – sean

+0

Das ist genau das, was ich wollte! Vielen Dank! Ich muss den gleichen Controller als modalen Controller und als ng-Controller zu verwenden. Und für den modalen Controller brauche ich zusätzliche Resolver. –

5

auf diese Weise versuchen ..

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

'erfordert' ist ein Array von Abhängigkeits Modulen.Diese

9

ist, wie ich es gelöst:

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