InversifyJS
InversifyJS copied to clipboard
Entities with private container and lazyInject
- For example I have class AppFactoy with private Container
- I have multiple instances of AppFactoy that have their own bindings.
Simple raw sample with ordinary injections (not lazy):
it('testInject', () =>
{
class AppFactory
{
private container: Container = new Container({autoBindInjectable: true});
public mapToValue(type:any, to:any):void
{
if (this.container.isBound(type))
{
this.container.unbind(type);
}
this.container.bind(type).toConstantValue(to);
}
public getInstance(type:any):any
{
return this.container.get(type);
}
}
@injectable()
class Obj
{
@inject("string")
private _s:string;
get s(): string
{
return this._s;
}
}
class Main
{
private f_1:AppFactory = new AppFactory();
private f_2:AppFactory = new AppFactory();
constructor()
{
this.f_1.mapToValue("string", "aaa");
this.f_2.mapToValue("string", "bbb");
let o_1:Obj = this.f_1.getInstance(Obj);
let o_2:Obj = this.f_2.getInstance(Obj);
expect(o_1.s).equals("aaa");
expect(o_2.s).equals("bbb");
this.f_1.mapToValue(Obj, o_1);
this.f_2.mapToValue(Obj, o_2);
this.f_1.mapToValue("string", "ccc");
this.f_2.mapToValue("string", "ddd");
let o_3:Obj = this.f_1.getInstance(Obj);
let o_4:Obj = this.f_2.getInstance(Obj);
// which is correct, because values are not re-injected
expect(o_3.s).equals("aaa");
expect(o_4.s).equals("bbb");
}
}
new Main();
});
The question is how can I achieve this using lazy injection of private _s:string having separate lazyInject constants with each AppFactory container?
This is a workaround:
- We create globalContainer in static scope (or global scope? I don't know how to name it correctly).
- Before each lazy injection we merge bindings from AppFactory container into globalContainer and after we clear it by calling unbindAll. Though it works as I expect, may be there is a more elegant way to implement that?
it('testLazyInject', () =>
{
function copyDictionary(
origin: interfaces.Lookup<interfaces.Binding<any>>,
destination: interfaces.Lookup<interfaces.Binding<any>>
) {
origin.traverse((key, value) => {
value.forEach((binding) => {
destination.add(binding.serviceIdentifier, binding.clone());
});
});
}
const globalContainer: Container = new Container();
const {lazyInject} = getDecorators(globalContainer, false);
class AppFactory
{
public container: Container = new Container({autoBindInjectable: true});
public mapToValue(type:any, to:any, name?:string):void
{
if (!name)
{
if (this.container.isBound(type))
{
this.container.unbind(type);
}
this.container.bind(type).toConstantValue(to);
} else
{
if (this.container.isBoundNamed(type, name))
{
this.container.unbind(type);
}
this.container.bind(type).toConstantValue(to).whenTargetNamed(name);
}
}
public getInstance(type:any, name?:any):any
{
return !name ? this.container.get(type) : this.container.getNamed(type, name);
}
}
@injectable()
class Obj
{
@lazyInject("string")
private _s:string;
get s(): string
{
return this._s;
}
}
class Main
{
private f_1:AppFactory = new AppFactory();
private f_2:AppFactory = new AppFactory();
constructor()
{
this.f_1.mapToValue("string", "aaa");
this.f_2.mapToValue("string", "bbb");
copyDictionary(getBindingDictionary(this.f_1.container), getBindingDictionary(globalContainer));
let o_1:Obj = new Obj();
expect(o_1.s).equals("aaa");
globalContainer.unbindAll();
copyDictionary(getBindingDictionary(this.f_2.container), getBindingDictionary(globalContainer));
let o_2:Obj = new Obj();
expect(o_2.s).equals("bbb");
globalContainer.unbindAll();
this.f_1.mapToValue(Obj, o_1, "o1");
this.f_2.mapToValue(Obj, o_2, "o2");
this.f_1.mapToValue("string", "ccc");
this.f_2.mapToValue("string", "ddd");
copyDictionary(getBindingDictionary(this.f_1.container), getBindingDictionary(globalContainer));
let o_3:Obj = this.f_1.getInstance(Obj, "o1");
// string is re-injected to already existing objects
expect(o_3.s).equals("ccc");
globalContainer.unbindAll();
copyDictionary(getBindingDictionary(this.f_2.container), getBindingDictionary(globalContainer));
let o_4:Obj = this.f_2.getInstance(Obj, "o2");
// string is re-injected to already existing objects
expect(o_4.s).equals("ddd");
expect(o_3).equals(o_1);
expect(o_4).equals(o_2);
}
}
new Main();
});