3

I'm quite new to Angularjs and Typescript.

I'll try to keep things short here:

The directive (directives/BikeDirective.ts):

class BikeDirective {
    constructor() {
        var directive: ng.IDirective = {};
        directive.restrict = "E";
        directive.scope = {
            move: "="
        };
        directive.template = '<div>The bike</div>';
        directive.link = (scope, element, attrs: any) => {
            element.on('click', (e) => {
                scope.move('moving!');
            });
        }
        return directive;
    }
}
export = BikeDirective;

The Controller (controllers/MyController):

class MyController {
    whatever: string;
    constructor(public scope) {
        this.whatever = "Whatever";
        scope.vm = this;
    }
    onMove(msg: string) {
        console.log(this.whatever);
    }
}
export = MyController;

The HTML:

    <div ng-controller="myController">
        <my-bike move="vm.onMove"></my-bike>
        <my-bike move="vm.onMove"></my-bike>
    </div>

app.ts

import MyController = require("controllers/MyController");
import BikeDirective = require("directives/BikeDirective");

class app {
    constructor() {
        var app = angular.module('app', [])
            .controller('myController', ['$scope', MyController])
            .directive('myBike', [BikeDirective]);
    }
}
export = app;

main.ts

require.config({
    baseUrl: '.',
    paths: {
        jquery: './Scripts/jquery-2.1.0',
        angular: './Scripts/angular'
    },
    shim: {
        'angular': {
            exports: 'angular'
        }
    }
}); 
require(['app','angular','jquery'], (app, angular, $) => {
    new app;
    angular.bootstrap(document.body, ['app']);
});

I hope the above code is self explanatory. Basically, what I want to do is when clicking on one of the bikes (my-bike directive) the MyController.onMove() function is run. That all works fine. The only problem I am having is that when onMove is executed console.log(this.whatever) outputs undefined, shouldn't it output the string "whatever"? Seems like the scope of MyController is not available in the onMove() stub.

I tried this in plain Angularjs (without TypeScript) and it works fine, am I missing something.

Has anybody experienced this before?

I followed .vm technique used by Basarat in this video: http://www.youtube.com/watch?v=WdtVn_8K17E

Thanks

1 Answer 1

3

Issue

The issue is in move="vm.onMove" you are passing a reference to a function into the directive i.e.

        directive.scope = {
            move: "="
        };

Calling a reference to a function disconnects it from this.

Quick fix:

onMove = (msg: string) => {
    console.log(this.whatever); //OKAY
}

This explains this a bit more: https://www.youtube.com/watch?v=tvocUcbCupA&hd=1

Better fix:

Don't pass functions into directives i.e. don't use = with functions. Instead use & i.e.

        directive.scope = {
            move: "&"
        };

And then call it from your html i.e. <my-bike move="vm.onMove()"></my-bike>. Calling a function with vm. i.e. vm.onMove() ensures that this is correct inside the function.

Also not related to this issue

element.on callback is not called in the angular context ... so you might want to wrap the callback it in a $scope.$apply

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @basarat. That works perfectly. I initially did set the scope as "&", that was me experimenting with it. Your answer is great, but I don't have enough reputation points to mark it as the answer
@ZeroOne you cannot vote up/down answers at the beginning rep .. but you should always be able to mark as answer if you asked the question : stackoverflow.com/help/someone-answers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.