0

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.

Community
  • 1
  • 1
TKirahvi
  • 318
  • 3
  • 19

1 Answers1

7

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); 
dhavalcengg
  • 4,678
  • 1
  • 17
  • 25
  • Still says undefined :( I changed var directive... to: `var directive = (myService: Foo.MyService) => { console.log(myService); console.log(Foo.MyService); return new MyDirective(myService); } ` and both console.logs are undefined – TKirahvi Aug 06 '15 at 06:37
  • It seems our generated javascripts are pretty much identical apart from this: var self = this; How is this done in typescript? Although I'm not sure if that fixes my problem in factory (myService being undefined, when yours is Object as it should be) – TKirahvi Aug 06 '15 at 07:49
  • I have pasted typescript. Two changes (1) Use lambda expression in link method. It will create closure for you. (2) directive.$inject = ['myService'] in static factory method of directive class – dhavalcengg Aug 06 '15 at 07:59
  • Ok, now the service isn't undefined anymore but when trying to assign this.myService.getBar() to scope.foo, an error occurs: Error: [$compile:nonassign] Expression 'undefined' used with directive 'myDirective' is non-assignable! https://docs.angularjs.org/error/$compile/nonassign?p0=undefined&p1=myDirective – TKirahvi Aug 06 '15 at 08:23
  • This is a problem with your markup.. can you share your HTML? How you are using your directive? – dhavalcengg Aug 06 '15 at 08:27
  • So it was (I was missing foo attribute). Thank you so much! – TKirahvi Aug 06 '15 at 08:29
  • This example works fine but when I use service injection similarly in my bigger application, services get undefined often. If I for example add a console.log somewhere in the app, every service in every directive get undefined suddenly. And it stays that way for a while and then suddenly all works just fine again. This behaviour is very, very odd. – TKirahvi Aug 09 '15 at 07:50