Object Container
The Object Container (OC) is an enhanced dependency injector with support for aliases and constants. It is sophisticated and registers everything it comes across but only if it actually matters.
By registering controllers and views the OC can simply follow your dependency tree and register everything you might possibly need. Below is a diagram of simple dependency tree.
app/config/routes.js
├─ OrderController
| ├─ OrderService / OrderEntity
| | └─ RestClient
| | ├─ $HttpAgent
| | ├─ $Cache
| | └─ LinkGenerator
| | └─ $Router
| └─ UserService / UserEntity
| └─ RestClient
| ├─ $HttpAgent
| ├─ $Cache
| └─ LinkGenerator
| └─ $Router
└─ UserController
├─ ...
└─ ...
Automatic registration with Object Container
Every class that defines static property $dependencies
which exports array of dependencies is automatically registered to oc
and instanced when it is used (this can happen lazily upon first usage).
Manually registering dependencies
Since the OC cannot discover everything and doesn't know about interfaces you can register your dependencies in a file app/config/bind.js
.
This file contains a function that receives the namespace register
(deprecated), OC instance and a config object.
// app/config/bind.js
export let init = (ns, oc, config) => {
// Register stuff here
}
OC handles instances of registered dependencies. When registering a class, be aware that its static methods and properties won't be available through OC.
Below is list of methods that the OC provides to register your dependencies.
Note: Every method returns the OC itself so you can chain them together.
1. bind()
Binds the specified class or factory function and dependencies to the specified alias. This allows to create new instances of the class or the function by referencing the alias. Same goes for specifying the class of the function as a dependency.
Also note that the same class or function may be bound to several aliases and each may use different dependencies.
The alias will use the current dependencies bound to the class if no dependencies are provided.
// app/config/bind.js
//
// Binding custom router implementation and
// UserAgent class from IMA.js user-agent plugin
import { UserAgent } from '@ima/plugin-useragent';
import { CustomRouter } from 'app/your-custom-overrides/Router';
export let init = (ns, oc, config) => {
// Simple alias
oc.bind('UserAgent', UserAgent);
// Alias with dependencies
// Override of the IMA.js router implementation
oc.bind('$Router', CustomRouter, [
'$PageManager', '$RouteFactory', '$Dispatcher', Window
]);
// ...
}
Note: The dollar-sign
$
at the beginning of an alias marks IMA.js internal component.
2. constant()
Defines a new constant registered within the OC. Note that
this is the only way of passing string
values to constructors
because the OC treats strings as class, interface, alias
or constant names. Once the constant is defined it cannot be redefined.
// app/config/bind.js
//
// Assigning API root URL to a constant that can be later used as a dependency
// (for example in IMA.js RestAPI client)
export let init = (ns, oc, config) => {
oc.constant('REST_API_ROOT_URL', config.api.url);
}
Note: Constants are not limited to primitive values but can also take objects.
3. inject()
Configures the object loader with the specified default dependencies for the specified class.
New instances of the class created by the OC will receive the provided dependencies into constructor unless custom dependencies are provided.
// app/config/bind.js
//
// Injecting the rest client.
// Notice how we used the REST_API_ROOT_URL constant
import Cache from 'ima/cache/Cache';
import HttpAgent from 'ima/http/HttpAgent';
import SimpleRestClient from 'app/rest-client-impl/SimpleRestClient';
import LinkGenerator from 'app/rest-client-impl/LinkGenerator';
export let init = (ns, oc, config) => {
oc.inject(SimpleRestClient, [
HttpAgent, Cache, 'REST_API_ROOT_URL', LinkGenerator
]);
}
Note: For more information about the IMA.js REST Client see IMA-plugin-rest-client repository.
4. provide()
Configures the default implementation of the specified interface. When the interface is requested from the OC the default implementation is provided.
The implementation constructor will obtain the provided default
dependencies or the dependencies provided to the create()
method.
// app/config/bind.js
//
//
import { AbstractRestClient } from 'ima-plugin-rest-client';
import SimpleRestClient from 'app/rest-client-impl/SimpleRestClient';
export let init = (ns, oc, config) => {
oc.provide(AbstractRestClient, SimpleRestClient);
// We didn't specify any dependencies on purpose
// they were set in the previous example.
// Otherwise it would be like this:
oc.provide(
AbstractRestClient,
SimpleRestClient,
[
HttpAgent, Cache, 'REST_API_ROOT_URL', LinkGenerator
]
);
}