Kann ich einen Dienst in eine Direktive in AngularJS einfügen?

234

Ich versuche, einen Dienst in eine Richtlinie wie die folgende einzufügen:

 var app = angular.module('app',[]);
 app.factory('myData', function(){
     return {
        name : "myName"
     }
 });
 app.directive('changeIt',function($compile, myData){
    return {
            restrict: 'C',
            link: function (scope, element, attrs) {
                scope.name = myData.name;
            }
        }
 });

Aber das gibt mir einen Fehler zurück Unknown provider: myDataProvider. Könnte jemand bitte in den Code schauen und mir sagen, wenn ich etwas falsch mache?

Ausnahme
quelle

Antworten:

388

Sie können Direktiven injizieren, und es sieht genauso aus wie überall sonst.

app.directive('changeIt', ['myData', function(myData){
    return {
        restrict: 'C',
        link: function (scope, element, attrs) {
            scope.name = myData.name;
        }
    }
 }]);
Grendian
quelle
13
Ich denke, dies ist eine bessere Lösung, da es auch nach dem Minimieren Ihres Codes funktioniert.
Czerasz
5
Ich musste vor der Rückgabe {} '_myData = myData' hinzufügen und dann das Objekt innerhalb der Link-Funktion als _myData referenzieren.
Jelling
Danke @Jelling. Ich musste das Gleiche tun. Ich frage mich, ob uns da draußen jemand sagen könnte, warum ...?
Sfletche
6
Gibt es einen bestimmten Grund, $ compile in die Direktive einzufügen? es scheint nirgendwo verwendet zu werden.
gru
4
Gibt es eine Lösung für das Injizieren, wenn Sie die Link-Funktion außerhalb des Direktivenaufrufs erstellen möchten?
ThinkBonobo
19

Ändern Sie Ihre Direktivendefinition von app.modulenach app.directive. Ansonsten sieht alles gut aus. Übrigens müssen Sie sehr selten einen Dienst in eine Richtlinie einfügen. Wenn Sie einen Dienst (der normalerweise eine Datenquelle oder ein Modell ist) in Ihre Direktive (die Teil einer Ansicht ist) einfügen, erstellen Sie eine direkte Kopplung zwischen Ihrer Ansicht und Ihrem Modell. Sie müssen sie trennen, indem Sie sie mit einem Controller miteinander verbinden.

Es funktioniert gut. Ich bin nicht sicher, was Sie tun, was falsch ist. Hier funktioniert ein Teil davon.

http://plnkr.co/edit/M8omDEjvPvBtrBHM84Am

Ganaraj
quelle
Können Sie bitte ein Beispiel geben
Ausnahme
@Exception Kannst du deinen Code in eine Geige stecken? Ich kann nachsehen, warum Ihr Code nicht funktioniert, und Ihnen wahrscheinlich dabei helfen, ihn zu beheben.
Ganaraj
@Exception hat einen funktionierenden Plunk hinzugefügt, der zeigt, wie der Code funktioniert.
Ganaraj
3
Ich habe gerade etwas entdeckt: Wenn Sie eine Injektion in den Funktionsparametern definieren, sich function($location) { ...aber nicht auf $locationdie Funktion beziehen , führt AngularJS die Injektion nicht durch. Das einzige Mal, dass Sie dieses Verhalten jemals bemerken würden, ist im Debugger.
Walter Stabosz
13
Ich bin nicht sicher, ob ich Ihrem "gekoppelten" Kommentar zustimme. Wir koppeln den Controller und den Service bereits global - wir können die Implementierung des Service zur Laufzeit nicht programmatisch ersetzen. Dies bedeutet, dass ein einzelner Controller einen einzelnen Dienst erhält. Direktiven haben jedoch eine isolierte Konfiguration pro Tag auf der Seite, sodass wir möglicherweise unterschiedliche Dienste für unterschiedliche Direktiveninstanzen aktivieren. Mir scheint, das ist weniger entkoppelt.
Kerl Mograbi
11

Sie können auch den $ inj-Service verwenden, um den gewünschten Service zu erhalten. Ich finde das nützlich, wenn ich den Dienstnamen nicht im Voraus kenne, aber die Dienstschnittstelle kenne. Zum Beispiel eine Direktive, die eine Tabelle in einen ngResource-Endpunkt einfügt, oder eine generische Schaltfläche zum Löschen von Datensätzen, die mit einem beliebigen API-Endpunkt interagiert. Sie möchten die Tabellenanweisung nicht für jeden Controller oder jede Datenquelle erneut implementieren.

template.html

<div my-directive api-service='ServiceName'></div>

my-directive.directive.coffee

angular.module 'my.module'
  .factory 'myDirective', ($injector) ->
    directive = 
      restrict: 'A'
      link: (scope, element, attributes) ->
        scope.apiService = $injector.get(attributes.apiService)

Jetzt ist Ihr "anonymer" Dienst vollständig verfügbar. Wenn es sich beispielsweise um ngResource handelt, können Sie die Standardschnittstelle ngResource verwenden, um Ihre Daten abzurufen

Beispielsweise:

scope.apiService.query((response) ->
  scope.data = response
, (errorResponse) ->
  console.log "ERROR fetching data for service: #{attributes.apiService}"
  console.log errorResponse.data
)

Ich habe festgestellt, dass diese Technik sehr nützlich ist, wenn Elemente erstellt werden, die insbesondere mit API-Endpunkten interagieren.

Tyrone Wilson
quelle