Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

When creating a templated directive in Angular using TypeScript your scope interface not only represents what is coming into the directive, it also ends up representing what you need to bind to the view.

For instance, given the following HTML.

<my-widget my-title="vm.title"></my-widget>

The TypeScript directive might look like this.

module widgets {
    'use strict';

    export interface IWidgetScope extends ng.IScope {
        myTitle: string;
    }

    export class Widget implements ng.IDirective {

        public templateUrl = 'app/widgets/widget.html';
        public restrict = 'E';
        public scope: {[key: string] : string} = {
            'myTitle': '=',
        };

        public link: (scope: IWidgetScope, element: ng.IAugmentedJQuery,
                      attrs: ng.IAttributes) => void;

        static factory(): any {
            /* @ngInject */
            var directive = () => {
                return new Widget();
            };
            return directive;
        }

        constructor() {
            this.link = (scope: IWidgetScope,
                         element: ng.IAugmentedJQuery,
                         attrs: ng.IAttributes) => {
                var init = () => {
                    scope.handleAction = () => {
                        scope.myTitle='clicked';
                    };
                    scope.$apply();
                };
                element.ready(init);
            }
        }

    }
}

In widget.html you would have something like this.

<div ng-click="handleAction">
    <span>{{title}}</span>
</div>

The problem here is that the compiler will complain that handleAction is not a member of the IWidgetScope interface.

2339 Property 'handleAction' does not exist on type 'IWidgetScope'.

What is the recommended way of handling this situation? It seems like the problem is that the IWidgetScope is being forced to serve both sides external and internal.

Is this possible, or is any preferred?

share|improve this question
up vote 0 down vote accepted

I am using this approach to define a directive:

module widgets {
    'use strict';

    export interface IWidgetScope extends ng.IScope {
        myTitle: string;
    }

    export class Widget implements ng.IDirective {

        public templateUrl = 'app/widgets/widget.html';
        public restrict = 'E';
        public scope: {[key: string] : string} = {
            'myTitle': '=',
        };

        public controller = MyWidgetController;
        public controllerAs: string = "Ctrl";

        public link: (scope: IWidgetScope, element: ng.IAugmentedJQuery,
                      attrs: ng.IAttributes) => void;

        static factory(): any {
            /* @ngInject */
            var directive = () => {
                return new Widget();
            };
            return directive;
        }
    }
    export class MyWidgetController {
        static $inject = ["$scope", "$element", "$attr"];

        constructor(protected scope: IWidgetScope,
                   protected element : ng.IAugmentedJQuery,
                   protected attr : ng.IAttributes)
                   {
                   }

        public handleAction () {            
            this.scope.myTitle='clicked';            
        }

    }
}

And in template I can access controller methods with Ctrl. syntax

<div ng-click="Ctrl.handleAction()"> // this is from scope.Ctrl
    <span>{{title}}</span> // this is from scope
</div>

The TS code in a playground

There is a link to Q & A (and other links) with explanation how to create controller, directive... and also working plunkers:

share|improve this answer
    
This makes sense. It supports the Controller-As technique and helps to better visualize the difference between the isolate scope mapping and what internal methods the directive may have. – jedatu Nov 25 '15 at 6:22
    
Great to see that it could help a bit. Enjoy Typescript with Angular... good option... when Angular2 is coming... ;) – Radim Köhler Nov 25 '15 at 6:23
    
I am discovering that another benefit of this controller approach is the new bindToController feature which allows you to attach incoming directive data to the controller instead of scope. – jedatu Dec 5 '15 at 15:38
1  
Exactly. That way you are starting in fact - to think in angular 2 ;) – Radim Köhler Dec 5 '15 at 15:39

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.