Property injection in in AU1 (AU2 resolve)

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?

1 Like

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!

2 Likes
3 Likes

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.

3 Likes

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.

1 Like

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?

1 Like

Thanks @elitastic , 1.6.1 has been released with a fix for this abstract class as “interface”.

That went fast! :slight_smile: Thank you @bigopon!

I have just tested it and it works perfectly!

1 Like