TypeScript - 'this' reference in AngularJS event handler

// Controller using class
module App.Home {

    interface IHomeViewModel {
        title: string;
    }

    class HomeController implements IHomeViewModel {
        title: string = "Welcome!!!";

        static $inject = ["$location", "$rootScope"]
        constructor(
            private $location: ng.ILocationService,
            private $rootScope: ng.IRootScopeService) {
        }
    }

    angular.module("app")
        .controller("homeController", HomeController);
}

In this example, an interface called IHomeViewModel is created to represent the public members of the controller and a class HomeController is created which implements the interface.

Dependencies are injected using static $inject member and injected dependencies are declared as private members.

Here is an example of how we will add handler to Angular’s $routeChangeStart event which is raised when route change is initiated

// Event handlers
private hookEventHandlers():void {
        this.$rootScope.$on("$routeChangeStart", this.onRouteChangeStart);
}

private onRouteChangeStart():void {
        console.log(this.title);
}

The hookEventHandlers method is called from the constructor of the controller which adds handler to $routeChangeStart event and the handler simply logs title member of the class into console.

When this method is run, you would expect it to show ‘Welcome!!!’ in the console but it shows undefined instead.

This is happening because the caller of the method is NOT the instance of the class where it is defined, so this doesn’t have a member named title.

// Event handler using arrow function
private hookEventHandlers(): void {
        this.$rootScope.$on("$routeChangeStart",() => {
        this.onRouteChangeStart.call(this);
        });
}

private onRouteChangeStart(): void {
        console.log(this.title);
}

In this example, we have changed our event handler to be arrow function and the arrow function invokes onRouteChangeStart using call function and passing current instance of the class where it is defined as this reference.

But, how does arrow function has correct reference of this? When arrow function is created, this is lexically bound to the location where it is created. In this case, arrow function is created inside the member of a class where this represents the current instance of the class. So this reference inside the arrow function also represents the current instance of the class where it is created. That’s it :)

// Full code example
module App.Home {

    interface IHomeViewModel {
        title: string;
    }

    class HomeController implements IHomeViewModel {
        title: string = "Welcome!!!";

        static $inject = ["$location", "$rootScope"]
        constructor(
            private $location: ng.ILocationService,
            private $rootScope: ng.IRootScopeService) {

            this.hookEventHandlers();
        }

        private hookEventHandlers(): void {
            this.$rootScope.$on("$routeChangeStart",() =>; {
                this.onRouteChangeStart.call(this);
            });
        }

        private onRouteChangeStart(): void {
            console.log(this.title);
        }
    }

    angular.module("app")
        .controller("homeController", HomeController);
}
comments powered by Disqus