-
Notifications
You must be signed in to change notification settings - Fork 3
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. For example it registers only Controllers and Views that you use in app/config/routes.js
.
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
├─ ...
└─ ...
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
}
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.
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.
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.
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.
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
]
);
}
Apart from defining dependencies manually in app/config/bind.js
can every class (discovered by the OC) define a static getter $dependencies
. This getter should return list of dependencies specified by a class constructor or a string
alias.
// app/page/order/OrderController.js
//
// OrderController is discovered by the OC
// because it's registered in app/config/routes.js
import AbstractController from 'ima/controller/AbstractController';
import OrderService from 'app/model/order/OrderService.js';
import UserService from 'app/model/user/UserService.js';
export default class OrderController extends AbstractController {
static get $dependencies() {
return [
OrderService,
UserService,
'$Router'
];
}
// ...
Once you've defined the dependencies the constructor of the class will receiver their instances.
constructor(orderService, userService, $router) {
super();
this._orderService = orderService;
this._userService = userService;
this._$router = $router;
}
// ...
Retrieves the shared instance or value of the specified constant, alias, class or factory function, interface, or fully qualified namespace path (the method checks these in this order in case of a name clash).
The instance or value is created lazily the first time it is requested.
oc.get('REST_API_ROOT_URL');
oc.get('UserAgent');
oc.get(AbstractRestClient); // This returns instance of `SimpleRestClient` as we defined in the previous example
Creates a new instance of the class or retrieves the value generated by the factory function identified by the provided name, class, interface, or factory function, passing in the provided dependencies.
The method uses the dependencies specified when the class, interface or factory function has been registered with the object container if no custom dependencies are provided.
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';
oc.create('UserAgent');
oc.create(
SimpleRestClient,
[
HttpAgent, Cache, 'REST_API_ROOT_URL', LinkGenerator
]
);
The last two method are not used as much as the first one but can be
useful inside the app/config/bind.js
and app/config/routes.js
Returns true
if the specified object, class or resource isregistered
within the OC.
if (oc.has('UserAgent') && oc.get('UserAgent').isMobile()) {
// Register conditional stuff here...
}
Returns the class constructor function of the specified class or alias.
- Introduction
- Static view
- Adding some state
- Fetching the data from the server
- Writing posts
- Final polish