将服务/工厂注入指令

时间:2013-08-26 01:44:04

标签: angularjs angularjs-directive

我有两个/更多具有相同签名的服务。我可以动态注入到指令中吗?类似下面的内容

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

然后我应该能够使用下面的指令

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

我会添加更多具有相同签名的服务,我应该能够在不改变的情况下使用该指令,是否可能?

2 个答案:

答案 0 :(得分:14)

那是不可能的。您可以做的最好的事情是将指令范围绑定到其父范围的函数,该范围返回您的服务实例:

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

然后在你看来:

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

最后,您需要将getMyData()getYourData()添加到父作用域:

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

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

Plunker脚本here

我可以想到另一种方法:您可以创建一个抽象工厂并将其注入到指令中,然后将参数传递给指令,以便它可以告诉抽象工厂创建正确的服务。像这样:

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

现在你需要将类型传递给指令:

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

Plunker here

答案 1 :(得分:10)

这是一个解决方案,无需父控制器或工厂工厂。

在指令中,注入 $ injector 服务以检索工厂实例:

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

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

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

请注意,它正在控制器方法中发生。我无法使$ injector.get()在链接函数中工作。

模板:

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

- 编辑 -

链接功能中的工作解决方案:

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

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

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