TKirahvi TKirahvi - 5 months ago 27
AngularJS Question

Angular with Typescript and undefined injected service in directive

I'm trying to access services from directive but they seem to be undefined no matter what I do. MyDirective.factory() says undefined when initializing directive. Undefined also (not surprisingly) in the constructor.

I've tried to do similiar to these instructions with no avail:

http://blog.aaronholmes.net/writing-angularjs-directives-as-typescript-classes/

http://sirarsalih.com/2014/08/04/proper-dependency-injection-in-your-angularjs-typescript-apps/

Define AngularJS Directive using Typescript and $inject mechanism

Here's app.ts:

angular.module("fooTest", [])
.service("myService", Foo.MyService)
.directive("myDirective", Foo.MyDirective.factory());


MyDirective.ts:

module Foo {
'use strict';

export class MyDirective implements ng.IDirective {

private myService: any;

//static $inject = ['myService'];

constructor(service: MyService) {
this.myService = service;
}

restrict = "E";
replace = true;
template = "<div ng-click='fooClick()'>foo: {{foo}}</div>";
scope = {
foo: "="
};

link = (scope, element, attrs) => {
scope.fooClick = function () {
this.myService.foo();
scope.foo = this.myService.getBar();
}
};

static factory() {
console.log("factory");
var directive = (myService: Foo.MyService) => new MyDirective(myService);
directive['$inject'] = ['myService'];
return directive;
}
}
}


And MyService.ts:

module Foo {
'use strict';

export class MyService {

foo() {
console.log("bar");
}

getBar() {
return "bar";
}
}
}




EDIT:

The Foo example above works just fine with the help of the answer below but when I use similiar way to inject services in my real application, it functions very oddly. Everything may be working fine for a while but then if I add a console.log() somewhere (or do something else irrelevant to functionality) all (or some) of the services get undefined all of a sudden. This is very weird behaviour and very frustrating.

I have several directives in my app and directives within directives. It seems like sometimes all services aren't loaded properly or something and I've also tried to change the set up of the app.

I tried to copy this behaviour to this Foo example and it seems I made it happen by using another directive within the first one. Then services get undefined randomly.

In MyDirective.ts template is now:

template = "<div><div ng-click='fooClick()'>foo: {{foo}}</div><br/><another-directive test='bar'></another-directive></div>";


And AnotherDirective.ts:

module Foo {
'use strict';

export class AnotherDirective implements ng.IDirective {

private myService: any;

constructor(public service: MyService) {
this.myService = service;
}

restrict = "E";
replace = true;
template = "<div ng-click='barClick()'>bar: {{test}}</div>";
scope = {
test: "="
};

link = (scope, element, attrs) => {
scope.barClick = () => {
//console.log(this.myService);
scope.test = this.myService.getFoo();
}
};

static factory(): ng.IDirectiveFactory {
var directive = (myService: Foo.MyService) => new AnotherDirective(myService);
directive.$inject = ['myService'];
return directive;
}

}
}


If I uncomment/comment console.logs in either directive, then services get undefined. Or if I do something else irrelevant to functionality. What the hell?

If I use console.log(this) within link function it shows "AnotherDirective { myService: Object..." when it works. But when it fails it shows "Scope {$id: 3, $$childTail: null, $$childHead:..."

In _references.ts which I include in app.ts the order is MyService, AnotherDirective, MyDirective, app.

Answer

change you factory method to following. You need to inject service in your directive's prototype.

  static factory() {
        console.log("factory");
        var directive = (myService: Foo.MyService) => new MyDirective(myService);
        directive.$inject = ['myService'];
        return directive;
    }

Checkout this http://plnkr.co/edit/DnU3N2BBZXCpdmmVZNbA?p=preview

Typescript

module Foo {
'use strict';

export class MyDirective implements ng.IDirective {

    private myService: any;

    //static $inject = ['myService'];

    constructor(service: MyService) {
        this.myService = service;
    }

    restrict = "E";
    replace = true;
    template = "<div ng-click='fooClick()'>foo: {{foo}}</div>";
    scope = {
        foo: "="
    };

    link = (scope, element, attrs) => {
        scope.fooClick =  () => {
            this.myService.foo();
            scope.foo = this.myService.getBar();
        }
    };

    static factory() {
        console.log("factory");
        var directive = (myService: Foo.MyService) => new MyDirective(myService);
        directive.$inject = ['myService'];
        return directive;
    }
}
}

module Foo {
    'use strict';

    export class MyService {

    foo() {
        console.log("bar");
    }

    getBar() {
        return "bar";
    }
}
}

angular.module("fooTest", []).
    directive("myDirective", Foo.MyDirective.factory()).
    service("myService", Foo.MyService); 
Comments