I'm building an application with angular and recently switched to TypeScript. The core of my application consists of multiple actual classes that interact with eachother (so not just global services). The way I did this is as follows:

class Person {
    constructor(private $http, public name: string) {
        // ... use this.$http for some task
    }
}

class PersonFactory {
    static $inject = ['$http'];

    constructor(private $http) {}

    create(name: string) {
        return new Person(this.$http, name);
    }
}

angular.module('app').service('personFactory', PersonFactory);

So if some other class needs to create a Person object, it needs to get injected with PersonFactory and call its create method. This works ok, even though it requires some boilerplate.

My main problem arises when I want to subclass Person:

class Student extends Person {
    constructor(private $http) {
        super(this.$http, 'Some actual name')
    }
}

I could follow the same pattern as above, but then I need to, again, create a StudentFactory that passes the required services like $http to the class constructor, which in turn passes it to the constructor of the super method. If I now had multiple such extending classes and would change the base class Person, I had to change every extending class and their factories. Is there a better way to approach this problem? Might it be better to just remove all dependencies on angular services in my core application and just use angular for the UI code?

Solution

As suggested in the answers, I added the $injector service to the window, like this:

module('app').run(['$injector', function($injector) {
    window.$injector = $injector;
}]);

The service can now be used in any class to get other services like $http. This didn't work for unit tests though, so I had to put the injector on the global scope again:

// MyClass.test.js
var $injector;

describe('My class', function() {
    beforeEach(module('app'));

    beforeEach(inject(function(_$injector_) {
        $injector = _$injector_;
    }));

    ...
});
share|improve this question
up vote 1 down vote accepted

I had to change every extending class and their factories. Is there a better way to approach this problem

Just inject $injector and then the base class can get what it wants using $injector.get().

or even more crazy ... put $injector (its a singleton) on the global scope / or some module ... and just use that in your classes to get angular specific stuff.

share|improve this answer
    
So you would get rid off all the injection annotations and their corresponding constructor parameters and just use $injector.get() each time you need for example $http? For example some class method: makeApiCall() { $injector.get('$http').get(...).then(...); } and $injector would for example be a class member or as you suggested on the global scope. – qzr Oct 9 '15 at 7:20
    
To be honest ... I would even wrap up the angular injectables into a global var injectables e.g. injectables.$http , injectables.$timeout etc – basarat Oct 11 '15 at 22:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.