I have decided to shift my approach in writing AngularJS apps from plain JavaScript to using TypeScript as a pre-processor.
One of my challenges lies in merging the two approaches, particularly when dealing with scoped method calls.
Let's take the example of a common menu scenario; I want to highlight a specific menu item that is currently active. The HTML template appears like this:
<ul class="nav navbar-nav">
...
<li ng-class="{active: isSelected('/page1')}"><a href="#/page1">Page 1</a></li>
...
</ul>
This requires a scoped function named isSelected
. In traditional JavaScript coding, I would define it as follows:
$scope.isSelected = function(path) {
return $location.path().substr(0, path.length) == path;
}
However, this anonymous function doesn't align well with the class model conventions of TypeScript. In TypeScript, I am inclined to write something like this:
export interface MenuScope extends ng.IScope {
isSelected(path: String): boolean;
}
export class MenuController {
location: ng.ILocationService;
scope: MenuScope;
constructor($scope: MenuScope, $location: ng.ILocationService) {
this.scope = $scope;
this.location = $location;
this.scope.isSelected = function(path) { return this.isSelected(path) }.bind(this);
}
isSelected(path: String): boolean {
return this.location.path().substr(0, path.length) == path;
}
}
Here, isSelected
belongs to the controller rather than the scope, which makes more sense. However, there is still a dependency on an anonymous method to link the scope and controller together.
Moreover, I had to explicitly bind the context of this
in order to access the location service within the implementation of isSelected()
.
My goal in transitioning to TypeScript was to improve code clarity, but this process of indirection through binding an anonymous function seems counterproductive to that aim.