Injection With Inheritance in Aurelia

Last updated: November 18, 2016

In Aurelia if you have a parent/base class and one or more children that inherit from this class AND the parent class has some injectables via Aurelia’s dependency injection container, you have most likely encountered an issue with needing to import and pass the dependencies back to the parent.

You might have done something like this:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class Parent {
    constructor(router) {
        this.router = router;
    }
}
import {Parent} from './parent';
import {Router} from 'aurelia-router';

@inject(Router)
export class Child extends Parent {
    constructor(router) {
        super(router);
    }
}

Gross.

Or maybe you imported the container directly and did this in your parent/base class:

import {Container} from 'aurelia-framework';
import {Router} from 'aurelia-router';

export class Parent {
    constructor() {
        this.router = Container.instance.get(Router);
    }
}

A little bit better, but still, there is no need to directly access the DI container for such a thing.

What if I told you there was a better way? Let’s use the spread operator and rest parameters to get our parent dependencies:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class Parent {
    constructor(router) {
        this.router = router;
    }
}
import {Parent} from './parent';

export class Child extends Parent {
    constructor(...rest) {
        super(...rest);
    }
}

Now what if you wanted to introduce a new dependency from within your child class? You can just do this:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class Parent {
    constructor(router) {
        this.router = router;
    }
}
import {inject} from 'aurelia-framework';
import {Parent} from './parent';

import {MyService} from './my-service';

@inject(MyService)
export class Child extends Parent {
    constructor(myService, ...rest) {
        super(...rest);
        this.myService = myService;
    }
}

You gotta love Aurelia, sometimes it feels like it makes some things a little TOO EASY.

Purchase Aurelia for Real World Applications over at Leanpub now

 

Dwayne

 

9 thoughts on “Injection With Inheritance in Aurelia

  1. the real problem of VM inheritance are the bindables not being registered on children. Quite possibly the biggest headache when trying to have the most maintainable code.

  2. I’ve tried doing something very similar and I get “Supplied parameters do not match any signature of call target” on the child calls to super(…rest). Any ideas?

  3. Not working with Typescript. It seems like spread operator cannot be used with super(…rest) call in TS.

  4. @petronellius

    What version of TypeScript are you running? Support was added in a little while ago for rest/spread operators.

  5. I don’t think this actually solves the problem.

    In your Child class, try the following:

    1) Remove the Router import
    2) Remove the Router injection

    In other words, simply provide a constructor signature and a super signature with a number of args matching the number of arguments in the Parent class’ constructor.

    You will see that it still works. In other words, importing and injecting dependencies in the Child class and passing them to the Parent class appears to have never been necessary. It’s the signatures that matter.

  6. Google never fails to amaze me! I literally googled “Aurelia Inheritance” and landed here on this beaut. Nice work, Sir.

Leave a Reply

Your email address will not be published. Required fields are marked *