2013-08-26 11 views
6

Ich habe zwei/mehr Dienste mit der gleichen Unterschrift. Kann ich mich dann dynamisch in die Direktive einspritzen? so etwas wie untenInjektion Service/Fabrik zu Richtlinie

var app = angular.module('app',[]); 
app.factory('myData', function(){ 
    return { 
     name : "myName", 
     id : 1, 
     create: function(){ 
      //do something 
     } 
    } 
}); 
app.factory('yourData', function(){ 
    return { 
     name : "yourName", 
     id : 1, 
     create: function(){ 
      //do something 
     } 
    } 
}); 
app.directive('changeIt',function($compile){ 
    return { 
     restrict: 'CA', 
     scope:{ 
      data : '=' //or some oether syntax? 
     }, 
     link: function (scope, element, attrs) { 
      scope.name = data.name; 
     } 
    } 
}); 

Dann sollte ich in der Lage sein, um die Richtlinie zu verwenden, wie unten

<div class='change-it' data='myData'>{{name}}</div> 
<div class='change-it' data='yourData'>{{name}}</div> 

würde ich das Hinzufügen von mehr Dienste mit der gleichen Signatur und ich sollte die Richtlinie verwenden können, ohne zu ändern, ist es möglich?

Antwort

13

Das ist nicht so möglich. Das Beste, was Sie tun können, ist die Richtlinie Anwendungsbereich auf eine Funktion des übergeordneten Umfang binden, die eine Instanz des Service zurück:

app.directive('changeIt', function(){ 
    return { 
    restrict: 'CA', 
    scope: { getDataFn : '&' }, 
    link: function (scope) { 
     scope.name = getDataFn().name; 
    } 
    } 
});  

und dann in der Ansicht:

<div class='change-it' get-data-fn='getMyData()'></div> 
<div class='change-it' get-data-fn='getYourData()'></div> 

Schließlich müssen Sie hinzufügen getMyData() und getYourData() an den übergeordneten Bereich:

app.controller('Ctrl', function($scope, myData, yourData) { 
    $scope.getMyData = function() { 
    return myData; 
    }; 

    $scope.getYourData = function() { 
    return yourData; 
    }; 
}); 

Plunker Skript here.

Ich kann mir jedoch eine andere Herangehensweise vorstellen: Sie könnten eine abstrakte Factory erstellen und in die Direktive einfügen und dann einen Parameter an die Direktive übergeben, damit die abstrakte Factory den richtigen Service erstellen kann. Etwas wie folgt aus:

app.service('dataFactory', function(myData, yourData) { 
    this.create = function(type) { 
    if (type === 'myData') 
     return myData; 
    else if (type === 'yourData') 
     return yourData; 
    }; 
}); 

app.directive('changeIt', function(dataFactory){ 
    return { 
    restrict: 'CA', 
    scope: true , 
    link: function (scope, element, attrs) { 
     scope.name = dataFactory.create(attrs.type).name; 
    } 
    } 
}); 

Und jetzt müssen Sie die Art der Richtlinie zu übergeben:

<div class='change-it' type="myData"></div> 
<div class='change-it' type="yourData"></div> 

Plunker here.

+0

Beide Ansätze wirklich gut aussehen. – Murali

+0

Ich denke, dass Sie in der Lage sind, einen einfachen Controller zu definieren, der den Datencall ausführt und ihn an die Direktive übergibt. Ng-controller = "YourCtrl" –

+0

Wirklich hilfreich. Vielen Dank! –

9

Hier ist eine Lösung ohne die Notwendigkeit eines übergeordneten Controllers oder einer Fabrik von Fabriken.

In der Richtlinie, injizieren die $ Injektor Dienst die Factory-Instanz abzurufen:

app.directive('changeIt',function(){ 
     return { 
      scope:{ 
       factoryName : '@' 
      }, 
      controller: function ($scope, $injector) { 

       var factoryInstance = $injector.get($scope.factoryName); 

       $scope.name = factoryInstance.name; 
      } 
     } 
    }); 

Beachten Sie in der Controller-Methode geschieht es. Ich konnte $ injector.get() nicht in der Link-Funktion arbeiten.

Vorlage:

<div class='change-it' factory-name="myData"> {{ name }} </div> 
<div class='change-it' factory-name="yourData"> {{ name }} </div> 

- Bearbeiten -

Arbeitslösung in der Link-Funktion:

app.directive('changeIt',function(){ 
      return { 
       scope:{ 
        factoryName : '@' 
       }, 
       link: function (scope, element) { 

        var factoryInstance = element.injector().get(scope.factoryName); 

        scope.name = factoryInstance.name; 
       } 
      } 
     });