4

I'm a little bit confused about how angularjs application works.

First of all I should say I'm a newbie angularjs user but I'm familiar with other DI frameworks in other languages (like symfony in PHP, spring in Java, a bit Unity).

Each of these DI implementations requires class definitions and DI configuration.

Configuration usually includes:

  • how should be class injected (automatically by name or type, or manually)
  • if container should return a singleton instance
  • what factory class should be used for creating object
  • serviceIds - each service can be retrieved by serviceId. This serviceId says configuration of creating instance (what services should be injected and what params should be used).
  • etc.

And this configuration I'm missing in angularjs.

There is an dumb example how I expect such a configuration should work. I have two services, each does similar thing but with different implementation.

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

See http://jsfiddle.net/5ZDe6/1/

I would like to switch between LogNotifier and AlertNotifier without changing source code of DataLoader service. Is that possible?

Thank you

1 Answer 1

5

After a week fiddling with angularjs I realized one very important thing. All angularjs examples actually include the DI configuration I looked for. The configuration is actually a module definition itself.

All I had to do was to separate module definition from class definitions. Here is solved fiddle of my question - 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); 
    });
});

And there are class definitions separated from DI configuration.

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

I suppose that is the cleanest way how to achieve my requirements. Unfortunately if you really want to do this way you have to write a bit more code.

Frank

Sign up to request clarification or add additional context in comments.

1 Comment

I wonder how to bring AngularJS's elegant DI to PHP DIs. Currently PHP DIs seem too much like service containers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.