Dependency Resolvers

Dependency resolvers alter the default way a dependency is created. They are effectively a custom hook that will be invoked to get the dependency being built.

When registering items in the Container you can reference dependency resolvers via the inject() function. For example:

class MyClass {
    constructor(myStringValue, someOtherObject) {}
}
container
    .register('myClass', MyClass)
    .inject(
        { resolver: 'literal', value : 'the-string-to-inject' }, // a dependency key referencing a build in literal resolver
        'my-other-object-key' // plain old string dependency key
    );

There are 4 built in resolvers and you can create your own if required.

Built in Resolvers

Literal

This is handy if you want to inject a literal value, for example a string, into a dependency.

class MyClass {
    constructor(name) {
        this.name = name;
    }
    hello() {
        console.log(`Hello ${this.name}`);
    }
}
let container = new Container();
container
    .register('myClass', MyClass)
    .inject({ resolver: 'literal', value : 'world' });
let myClassInstance = container.resolve('myClass');
myClassInstance.hello(); // prints 'Hello world'

Delegate

The delegate resolver defers object creation to a delegate provided by the dependencyKey.

class Foo  {
    constructor(bar) {
        console.log('bar is : [%s]', bar);
    }
}
let container = new Container();
container.register('foo', Foo)
    .inject(
    {
        // Internally the container registers a resolver by key 'delegate'
        resolver: 'delegate',
        // use this function to create the dependency 
        resolve: (container, resolveKey) => {
            return 'barInstance';
        }
    });
let foo = container.resolve('foo');

Output:

bar is : [barInstance]

Injection Factory

The factories discussed under Object Factories are implemented using the built in factory dependency resolver.

External Factory

Under the covers registerFactory uses a built in externalFactory dependency resolver to invoke the factory registered against an identifier.

Custom Resolvers

A dependency resolver is simply an object with a resolve(container, dependencyKey) method. The container argument will be the current container (i.e. the container or child container which resolve() was called on), and the dependencyKey argument is the object passed to the inject(dependencyKey) function. You can create your own resolvers and add them to the container.

Example 1

Here is an example where an object injected into a dependency is resolved using a custom resolver.

class DomResolver {
    resolve(container, dependencyKey) {
        // return a pretend dom element,
        return {
            get description() {
                return 'Fake DOM element - ' + dependencyKey.domId ;
            }
        };
    }
}
let container = new Container();
container.addResolver('domResolver', new DomResolver());
class Controller {
    constructor(view) {
        console.log(view.description);
    }
}
container
    .register('controller', Controller)
    .inject(
        { resolver: 'domResolver', domId : 'viewId' } // this object is the 'dependencyKey'
    );
let controller = container.resolve('controller');

Output:

Fake DOM element - viewId

Example 2

This is a much more edge case example whereby you don’t know the type of the object you’re registering. Rather than registering a class or object to build, we pass a dependencyKey to the register() API. In this example, we emulate the fetching of a DOM node when resolving the dependency view.

class DomResolver {
    resolve(container, dependencyKey) {
        // return a pretend dom element,
        return {
            get description() {
                return 'Fake DOM element - ' + dependencyKey.domId ;
            }
        };
    }
}
let container = new Container();
container.addResolver('domResolver', new DomResolver());
// When using a resolve key to create the registered item we need to add a 'isdependencyKey' property. 
// This lets the container know the object you're passing to `register` isn't what should be returned when something calls resolve, 
// rather it'll use this object to create the object in question and return that to the caller. 
container.register('view', { resolver: 'domResolver', domId : 'theDomId', isdependencyKey: true });
let view = container.resolve('view');
console.log(view.description);

Output:

Fake DOM element - theDomId