In inversify-binding-decorators. The following should NOT throw an exception Cannot apply @injectable decorator multiple times:
@provide("SomeInterface")
@provide("SomeOtherInterface", true) // new argument!!
class SomeClass {
// ....
}
The new argument allows us to disable the exception.
The following throws an exception Cannot apply @injectable decorator multiple times:
@provide("SomeInterface")
@provide("SomeOtherInterface")
class SomeClass {
// ....
}
metadata_keys.ts in inversify.tsexport { Container } from "./container/container";
export { ContainerModule } from "./container/container_module";
export { injectable } from "./annotation/injectable";
export { tagged } from "./annotation/tagged";
export { named } from "./annotation/named";
// ...
import * as METADATA_KEY from "./constants/metadata_keys.ts";
export { METADATA_KEY };
METADATA_KEY.PARAM_TYPES and new force argument in provide.ts.Tip: Use @provide("ServiceIdentifier", true) if you are trying to declare multiple bindings! when th exception is thrown:import { decorate, injectable, METADATA_KEY } from "inversify";
import { interfaces } from "inversify";
function provide(container: interfaces.Container) {
// function is named for testing
return function _provide(
serviceIdentifier: interfaces.ServiceIdentifier<any>,
force?: boolean
) {
let bindingWhenOnSyntax = container.bind<any>(serviceIdentifier).to(<any>null);
return function (target: any) {
if (
force === true &&
Reflect.hasOwnMetadata(METADATA_KEY.PARAM_TYPES, target) === false
) {
decorate(injectable(), target);
} else {
try {
decorate(injectable(), target);
} catch(e) {
throw new Error(`
${e.message}
Please use @provide("ServiceIdentifier", true) if
you are trying to declare multiple bindings!
`)
}
}
let binding: interfaces.Binding<any> = (<any>bindingWhenOnSyntax)._binding;
binding.implementationType = target;
return target;
};
};
}
export default provide;
Decorate multiple times with @provide a class:
@provide("SomeInterface")
@provide("SomeOtherInterface")
class SomeClass {
// ....
}
This issue is a response to #53
One of the :fire: and most requested features for us!
@PowerMogli would you like to try to send a PR, one of the reasons I didn't do it already is because it is an easy change and I was waiting for someone that maybe wants to contribute for the first time...
This is now done by https://github.com/inversify/inversify-binding-decorators/pull/64 and it is available in [email protected].
Ah cool. You fixed it very fast. But unfortunately we use makeFluentProvideDecorator to generate a @provideFluent instead of @provide. The reason is we have a function defined like this:
const container = new Container();
const provideFluent = makeFluentProvideDecorator(container);
const provideSingleton = (identifier: any) => {
return provideFluent(identifier)
.inSingletonScope()
.done();
};
Do you have any tip how we can apply your commit to makeFluentProviderDecorator?
@PowerMogli Done :tada: https://github.com/inversify/inversify-binding-decorators/pull/65 and released in [email protected]
It works great, but we see a big problem: providing the decorator multiple times, inversify creates every time a new instance of the decorated class. Our intention was to generate only one instance of the class but decorated by multiple different identifiers.
Lets consider the following example:
@provideSingleton(VIEWSTATE.ViewStateSynchronizer)
@provideSingleton(TYPE.PatientComponentModel)
export class PatientComponentModel extends BaseComponentModel<IPatient>, IViewStateSynchronizer {
....
}
export class PatienComponent {
@lazyInject(TYPE.PatientComponentModel) patientComponentModel: PatientComponentModel;
....
}
export class DataSync {
constructor(@multiInject(VIEWSTATE.ViewStateSynchronizer) private viewStateSynchronizers: IViewStateSynchronizer[]){}
...
}
DataSyns service and the PatientComponent (Angular 2) have to get the same instance of PatientComponentModel injected. But both have to inject it by a different identifier.
I hope I could explain it clear enough and you can help us out here (again) 馃憤
@PowerMogli I think I get you. Do you mind creating a separate issue, please? This feature could be complicated.
We probably want something like:
@provideSingleton(VIEWSTATE.ViewStateSynchronizer, TYPE.PatientComponentModel)
But that would require:
container.bind(VIEWSTATE.ViewStateSynchronizer, TYPE.PatientComponentModel)
.to(PatientComponentModel)
Which I'm not sure about being possible. Let me think about this one because I think I can come up with a workaround. I will get back to you ASAP
@PowerMogli Did an issue ever get raised to cover your scenario above. I am trying to accomplish exactly the same thing and am observing the same behavior where my "singleton" is created twice, once for each binding.
@remojansen Did you ever come up with the workaround, would be great if you could share if you did.
@Recodify Sorry, we did not raise an issue. Just because we moved away from InversifyJS to Angulars own DI with 'multiple' feature. And Angular had big problems when building our project with InversifyJS and in production mode.
Most helpful comment
Docs:
@providemultiple times@provideFluentmultiple times