如何在angularjs中配置依赖注入?

时间:2013-05-24 09:23:59

标签: javascript configuration angularjs dependency-injection

我对angularjs应用程序的工作原理有点困惑。

首先,我应该说我是新手angularjs 用户,但我熟悉其他语言中的其他DI框架(例如PHP中的symfony,Java中的spring,有点Unity)。

这些DI实现中的每一个都需要类定义和 DI配置

配置通常包括:

  • 应如何注入(自动按名称或类型,或手动)
  • 如果容器应返回单例实例
  • 应该使用什么工厂类来创建对象
  • serviceIds - serviceId可以检索每项服务。此serviceId表示创建实例的配置(应注入哪些服务以及应使用哪些参数)。

这个配置我在angularjs中缺失

有一个 dumb 示例我希望这样的配置应该如何工作。我有两个服务,每个服务类似的事情,但不同的实现

angular.module('notify', [], function($provide) {
    $provide.factory('LogNotifier', function($window) {
        return {
            messageMe: function(message) {
                $window.console.log(message);
            }
        }

    });
    $provide.factory('AlertNotifier', function($window) {
        return {
            messageMe: function(message) {
                $window.alert(message);
            }
        }
    });
});



angular.module('myModule', ['notify'], function($provide) {
  // as notifier dependency I must specify its type.
  // is there any way how I would configure after its definition
  // which notifier implementation should be used?
  $provide.factory('DataLoader', function(AlertNotifier) {
      var loader = {
          loadAllItems: function() {
              AlertNotifier.messageMe('Loading items');
              // let's asume there is ajax call and promise object return
              return [ 
                    {name: 'Item1'},
                    {name: 'Item2'}
                ];
          }
      }
      return loader;
  });
});

请参阅http://jsfiddle.net/5ZDe6/1/

我想在LogNotifier和AlertNotifier 之间切换,而不更改DataLoader服务的源代码。这可能吗?

谢谢

1 个答案:

答案 0 :(得分:5)

经过一周摆弄angularjs后,我意识到一件非常重要的事情。所有angularjs示例实际上都包含我查找的DI配置。 配置实际上是模块定义本身

我所要做的就是将模块定义与类定义分开。 这里解决了我的问题 - http://jsfiddle.net/5ZDe6/7/

/**
* app module configuration
*/
angular.module('app', ['debug'], function($provide) {
    var dataLoaderFactory = function(Notifier) {
        return new my.model.DataLoader(Notifier);
    }
    // if you want to change notifier just change this injection to AlertNotifier
    dataLoaderFactory.$inject = ['LogNotifier'];  
    // Specify factory with service ID DataLoader for class my.model.DataLoader
    $provide.factory('DataLoader', dataLoaderFactory);    
})
.controller('AppCtrl', my.controller.ItemCtrl); // you can even specify AppCtrl implementation (e.g. CachedCtrl)
my.controller.ItemCtrl.$inject = ['$scope','DataLoader']
my.controller.CachedCtrl.$inject = ['$scope']

/**
* debug module configuration
*/
angular.module('debug', [], function($provide) {
    $provide.factory('LogNotifier', function($window) {
       return new my.debug.LogNotifier($window);
    });
    $provide.factory('AlertNotifier', function($window) {
       return new my.debug.AlertNotifier($window); 
    });
});

还有与DI配置分开的类定义。

/**
* Controller class definition
*/
my = window.my || {};
my.controller = my.controller || {};
my.controller.ItemCtrl = function($scope, loader) {
    $scope.items = loader.loadAllItems();
};

my.controller.CachedCtrl = function($scope) {
    $scope.items = [
        { name: 'Cached ctrl value 1'},
        { name: 'Cached ctrl value 2'}
    ]
}

/**
* Model class definition
*/
my.model = my.model || {};
my.model.DataLoader = function(notifier) {
    this.notifier = notifier;
    this.loadAllItems = function() {
        this.notifier.messageMe('Loading items');
        // let's asume there is ajax call and promise object return
        return [ 
            {name: 'Item1'},
            {name: 'Item2'}
        ];
    };
};

/**
* Some debug classes definition
*/
my.debug = my.debug || {}
my.debug.LogNotifier = function($window) {
    this.$window = $window;
    this.messageMe = function(message) {
        this.$window.console.log(message);
    }
};
my.debug.AlertNotifier = function($window) {
    this.$window = $window;
    this.messageMe = function(message) {
        this.$window.alert(message);
    }
}

我认为这是达到我要求的最简洁方法。不幸的是,如果你真的想这样做,你必须写更多的代码