Dependency Injection into Util Classes


#1

Is it possible to work with Dependency Injection in your own Util classes/objects which are extending Ember.Object or with Mixins so that for example you can use a shared value (as a user object) throughout the whole application via Dependency Injection instead of referencing it from the App. namespace? Also, is this somehow possible in Ember App Kit?


#2

You need to use an application initializer. It’s fired when your application becomes ready, and it’s passed the application container. From there, you can register and inject objects.

Taken (roughly) from the Ember-Data code:

Em.onLoad('Ember.Application', function(Application) {
    Application.initializer({
        name: 'userWidgetInitializer',

        initialize: function(container, application) {
            // Register the object you want to inject. Let's say you want to inject the UserWidget class.
            application.register('widget:userWidget', App.UserWidget, { singleton: true });

            // Inject the user widget into every controller instance
            // Because we labeled it a singleton, all controllers will get the same instance
            // The widget can be accessed with the controller's `widget` property
            application.inject('controller', 'widget', 'widget:userWidget');
        }
    });
});

Also, note that you can only register Ember.js factories (classes) with the container. If you wanted to register a non-Ember object, see this question.


#3

Thanks @gordon_kristan - that’s also what I found out (actually I’m registering and injecting util classes in Controllers and Routes like this) :smile:

What I really wanted to know is, how I could inject these dependencies into other Util classes which are not part of the Ember Framework (like Controller or Route) and how I could probably access the container from these classes to make use of it (by calling container.lookup('session_util:app') or something like this).

Actually I created a ApplicationContainer class which is nothing but a new Ember.Container() and import it in every Util class I need it… but this seems like bad practice to me :frowning:


#4

I think registering your utility classes with the container will automatically inject a container instance into them. So if you register your Widget class with the container, all Widget instances will now contain a container property that you can use.


#5

As far as I can tell, dependency injection doesn’t apply when you manually create utility classes. It only happens when using Container.lookup or when using the factory provided by Container.lookupFactory. The registered objects don’t seem to have access to container either way.

App = Ember.Application.create();

App.IndexRoute = Ember.Route.extend({
    setupController: function(controller) {
        // Created like a basic Ember.Object.
        var obj1 = App.MyObject.create();
        console.log('obj1.service', obj1.service);
        // Created by looking up the object in Container.
        var obj2 = this.container.lookup('object:main');
        console.log('obj2.service', obj2.service);
        // Created using the factory from Container.
        var objectFactory = this.container.lookupFactory('object:main');
        var obj3 = objectFactory.create();
        console.log('obj3.service', obj3.service);
    }
});

Ember.Application.initializer({
  name: 'injectMyObject',
    initialize: function(container, application) {
        application.register('object:main', App.MyObject, {singleton: false});
        application.register('service:main', App.MyService);
        application.inject('object', 'service', 'service:main');
    }
});

App.MyService = Ember.Object.extend();
App.MyObject = Ember.Object.extend();

See this JSFiddle: http://jsfiddle.net/theazureshadow/agzpbjsh/