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.

2
  • Is your service registered as myService or with a capital M MyService? Commented Aug 5, 2015 at 10:51
  • In the app.ts it registers as .service("myService", MyService), so without capital m. Commented Aug 6, 2015 at 6:06

1 Answer 1

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); 
Sign up to request clarification or add additional context in comments.

7 Comments

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
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)
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
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! docs.angularjs.org/error/$compile/…
This is a problem with your markup.. can you share your HTML? How you are using your directive?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.