I noticed through this that dependency injection and resolution will change in Aurelia 2.
This made me aware of AU2 resolve
for property injection which seems to be quite more usable than constructor parameters (notably, it would remove the need of having to write constructors in derived classes when more and more services are added).
Is there an equivalent in Aurelia 1?
resolve
can be back ported to v1, probably there shouldn’t be any issues making this not possible. Can you help create an issue for this?
That would be great! This could help us prepare for the migration to Au 2!
EDIT: THIS IS UNRELIABLE, see below.
I tried an extremely naĂŻve approach which on a test application seems to work:
// resolve.ts
import { Container } from "aurelia-framework"; // or aurelia-dependency-injection
export class Resolver {
static container: Container;
}
export function resolve<T>(ctor: { new(...args: any[]): T }) {
return Resolver.container.get(ctor) as T;
}
// main.ts - application entry point
import type { Aurelia } from "aurelia-framework";
import { Resolver } from "./resolve";
export async function configure(aurelia: Aurelia) {
aurelia.use.standardConfiguration();
Resolver.container = aurelia.container;
await aurelia.start();
await aurelia.setRoot();
}
// any class
import { resolve } from "./resolve";
import { MyService } from "./myService";
export class MyComponent {
readonly service = resolve(MyService);
}
That is, I intercept the root container during startup, save a reference to it somewhere and call it when needed through a custom resolve
function.
This is obviously extremely naĂŻve and limited to the very specific case of
- only one container (no child containers)
- only singleton services (no
NewInstance.of
and the like)
I have NOT tested this with our actual full application, but I expect it to work due to satisfying these constraints in most cases (we use NewInstance.of
only rarely).
Consider this code public domain and feel free to use it as-is or a a starting point to cover more complex cases.
EDIT: it turns out Aurelia uses child containers internally (which I noticed by trying to inject a DialogController
in a dialog), so this approach works only in extremely simple cases and needs further elaboration.
backport PR is available at feat: backport resolve by bigopon · Pull Request #228 · aurelia/dependency-injection · GitHub
Will be merging and getting a new version out soon. Thanks everyone.
aurelia-dependency-injection@1.6.0
is out with the above feature, for anyone who is interested
You can import the resolve
function from either aurelia-framework
or aurelia-dependency-injection
package, and the usage will be just the same with v2 resolve
.
Thank for backporting resolve()
@bigopon
Unfortunately, we have an issue with it, as we’re using abstract classes for DI:
// "interface"
export abstract class IMyService {
abstract func();
}
// implementation
export class MyService implements IMyService {
func() {
...
}
}
current code:
@autoinject
export class MyComponent {
constructor(
private myService: IMyService)
{
}
}
new code (not working)
export class MyComponent {
constructor(
// ==> myService is of type "typeof IMyService"
private myService = resolve(IMyService))
{
}
test() {
// ==> typescript error "Property func does not exist on type typeof IUserContext"
this.myService.func();
}
}
Is it possible to support this scenario?
Thanks @elitastic , 1.6.1 has been released with a fix for this abstract class as “interface”.
That went fast! Thank you @bigopon!
I have just tested it and it works perfectly!