Does Aurelia support Dependency Injection of non-Aurelia lib?

So I created Slickgrid-Universal as a monorepo and it is also a framework agnostic library. One the biggest reason I’ve created that lib was to extract all the common code that I have in Angular-Slickgrid and Aurelia-Slickgrid, they share a big portion of common code, something like 80%… So anyway, I’m now ready to go to the next step which is to start rewriting, mainly deleting a lot of code in Aurelia-Slickgrid and start using the common code from Slickgrid-Universal (which again is a framework agnostic lib)… but now I’m blocked at the Dependency Injection part, if I use @inject(MyService) inside Aurelia-Slickgrid, it does go into its constructor but I have plenty of services calling other services and they all come back as undefined and they don’t call their sub-services. I thought that perhaps I’m missing a small DI system in Slickgrid-Universal and I tried to implement TypeDI which is small and might be the cousin of TypeORM but that doesn’t do anything. It seems that Aurelia doesn’t know what to do with these services apart from just calling new MyService() without any of it’s other sub-services inside the MyService constructor.

So the question is… does Aurelia v1 support DI of other lib which multiple services calling themselves multiple services? For example this GridState Service calls multiple other services via in its constructor, is it possible to make Aurelia aware of what is has to do when calling each constructor?

If that doesn’t work, the worst case is not that bad, I can still get it to work by instantiating all services manually like I’ve done in my vanilla implementation on this line but I would rather use Aurelia DI and let it handle DI as much as possible (if it is actually possible)… anyway that is still a plan B

1 Like

There is always the option to get hold of the aurelia.container and registerInstance/Singleton/…as you need. I wonder though if there is a way to tell the DI to automatically handle all unknown classes as e.g. singletons from outside dependencies. Like a fallback resolver. Perhaps @bigopon has an idea how to do it in v1 and ideally also the same use case for v2

Edit:
Oh didnt notice that container.autoRegister(fn: any, key?: any): Resolver has an optional key, so that might already do the job

1 Like

The other problem that I had too in the past with Aurelia-Slickgrid is that most Services can’t be singleton or at least not in each created component (you obviously don’t want services from 2nd grid to affect 1st grid) and for that I had to add @singleton(true) to all my Services I had and that fixed it but I wonder how this will work if I even get the DI to work, they might be all singleton and that won’t work in my scenario.

I’ll take a look at that autoRegister, if anyone have sample that could be helpful too

1 Like

In this case you’d need a child container created per grid instance. This makes sure that upon request of a Service you get a per grid resolved instance

1 Like

I think that the easiest, and probably safest, at this point would be to create all instances manually (like I did in Slickgrid-Universal vanilla implementation here and I know it works since that is what I use in Salesforce) and then try out some of the Aurelia container features to try to find what works later on. At least this wouldn’t block me from going further in the implementation of my external monorepo lib (Slickgrid-Universal) within Aurelia-Slickgrid. The main goal of this post was “is this possible” and it looks like there are few options to try.

2 Likes

I think this is possible, with some rules: for vanilla only, it must be used with some static method to orchestrate the dependency creation/distribution. For framework, it’s simpler, and can be done in 3 ways:

  1. define the information needed for dependency injection at the class, like static inject in Aurelia, or the equivalent in Angular
  2. define a custom resolver in the consumer library, via a bridge. An example with Aurelia, in v2 is:
import { Registration } from 'aurelia';

export const SlickGridRegistration = {
  register(container) {
    Registration.callback;
    Registration.cachedCallback;
    Registration.instance
    // etc...
  }
}
  1. define an abstraction layer for service locating in SlickGrid universal, and build the bridge for that in Aurelia/Angular:
export const SlickGridFactory = (serviceLocator) => {
  return {
    instantiate: () => {
      const pubsubService = serviceLocator.get(EventPubSubService);
      // etc...
    }
  }
}

(3) can also be used in vanilla only version, basically you get a minimal, specific implementation of DI

The bottom line is there must always be some glue code to tie two different realms together. And it depends on how you want the API to be

1 Like

Some updates… I got the lib working (all 350+ Cypress UI tests passing) by using the external monorepo (Slickgrid-Universal) within Aurelia-Slickgrid and I’m about 70% done with the work. I’m currently instantiating all Services manually and it works for 95% of the cases, the only 5% not working are 2 Slickgrid Filters that have collection watch (via Aurelia BindingEngine) and that requires to extends services from Slickgrid-Universal into Aurelia-Slickgrid and injecting Aurelia BindingEngine and I can’t get that part going without DI it seems.

@bigopon is that possible with Au1 or just with Au2? …just asking since you mentioned Au2 and I haven’t tried Au2 yet. Just curious, if I switch my lib to Au2 (I wasn’t planning to do that any time soon but what if), will my lib be usable in Au1 code?

@zewa666 you probably understand the subject more than I do, that would be really nice if you could help on this. I have pushed my code to the branch (see below) and you could push directly on the same branch if you wish (and you are collaborator to the lib in GitHub so you should have access to push directly to the branch)

Here’s my branch update so far, this will most probably be my biggest PR ever (especially for amount of deleted lines lol)…

1 Like

It is possible with both version. The glueing code will be different for v1 and v2, but the core idea is the same: a mini specific DI that plug into aurelia DI, probably

1 Like