Skip to content

Injecting Dependencies

Brian Kotek edited this page Aug 20, 2013 · 25 revisions

Back to Core Features

Next, let's take a look at how the Deft JS IoC container is used. Consider the MainViewController class we just created. Recall that in my IoC configuration, I had set up a dependency provider for the CompanyStore class named companyStore. If I wanted to use the CompanyStore object in MainViewController, all I need to do is specify the name of that dependency provider using the inject property, like this:

Ext.define("DeftQuickStart.controller.MainController", {
  extend: "Deft.mvc.ViewController",
  inject: ["companyStore"],

  config: {
    companyStore: null
  },

  init: function() {
    return this.callParent(arguments);
  }

});

In the above example, I'm also setting up a config value for companyStore, so that Ext JS will create a getter and setter for that property. This is optional, but it's good practice.

How It Works

When Deft JS finds an inject property in one of your classes, it goes and looks for a corresponding dependency provider in the IoC configuration. If it finds one, it creates a singleton instance of the dependent class (if it hasn't already been created), and then resolves the dependency by populating the target property with the dependent object. So in this case, DeftJS will create an instance of CompanyStore and set it into the companyStore property of my MainViewController. All of this happens automatically, using class preprocessors.

Again, there are some more advanced IoC configuration options that allow you to specify a dependency provider as a singleton or a prototype object, as well as controlling lazy vs. eager creation of dependency providers. We'll look at these options a bit later.

DeftJS handles the injections and resolves the dependencies before the constructors of your classes run. That means the injected dependencies are available for use even in your constructors!

Folks with some experience using the Sencha platform might have noticed that I didn't specify the CompanyStore class in a requries property in the MainViewController. That's because I don't need to. DeftJS takes care of making sure the dependent class file is registered with ExtJS as being required.

You can specify an inject property on any of your classes. So ViewControllers, models, and view classes can all have dependencies injected into them. You can even inject dependencies into other dependency providers. In other words, if you have a CompanyService class and a CompanyStore class set up as dependency providers, the CompanyService class could specify companyStore in its inject tag. This would inject the CompanyStore into the CompanyService. So you can build up entire hierarchies of dependencies if you need to.

Beware Circular Dependencies: The only major caveat on injecting dependencies into other dependency providers is to watch out for circular dependencies. If DependencyA tries to inject DependencyB, but DependencyB wants DependencyA injected, we run into a "chicken-and-egg" problem.

As you may have noticed, by default DeftJS tries to inject the dependency into a property with the same name as the dependency provider. If you need to inject it into a different property, you can do that too:

Ext.define("DeftQuickStart.controller.MainController", {
  extend: "Deft.mvc.ViewController",
  inject: {
    myCompanyStore: "companyStore"
  },

  config: {
    myCompanyStore: null
  },

  init: function() {
    return this.callParent(arguments);
  }

});

Inheriting Injections

The inject property is handled differently than most other object properties. Normally, if a superclass declares a property and a subclass declares the same property, the subclass property overrides the superclass property. In most cases, this is what you want. In the case of injections, this would be a major limitation because you'd have to duplicate any parent class injections in all of its child classes.

When a superclass and a subclass both define injections, the injection configurations are merged together. This means you can declare common injections in a superclass, and more specific injections in subclasses. In cases where both superclass and subclass specify the same dependency provider name, the configuration in the subclass takes precedence.

Conclusion

That's really all there is to the most common and basic way to inject dependencies into your classes. Next, we'll look at how to access views from within our ViewControllers.

Next: Accessing Views