TypeScript 1.7+ annotations (decorators) for AngularJS 1.x
angular-typescript provides annotation like decorators:
@at.service(moduleName: string, serviceName: string)
@at.inject(dependencyOne: string, ...dependencies?: string[])
@at.controller(moduleName: string, controllerName: string)
@at.directive(moduleName: string, directiveName: string)
@at.classFactory(moduleName: string, className: string)
@at.resource(moduleName: string, resourceClassName: string)
Purpose of those decorators is to remove some ugly boilerplate from AngularJS applications written in TypeScript.
Now one have to:
class SomeService {
constructor() {
// do stuff $http and $parse
}
public someMethod(anArg: number): boolean {
// do some stuff
}
}
angular.module('ngModuleName').service('someService', SomeService);
Using angular-typescript it will look like:
@service('ngModuleName', 'someService')
class SomeService {
constructor() {
// do stuff
}
public someMethod(anArg: number): boolean {
// do some stuff
}
}
@service('ngModuleName', 'someServiceName')
class SomeService {
constructor(
@inject('$http') $http: angular.IHttpService,
@inject('$parse') private $$parse: angular.IParseService
) {
// do stuff with $http and $$parse;
}
public someMethod(anArg: number): boolean {
// do some stuff with this.$$parse
}
}
or
@service('ngModuleName', 'someServiceName')
@inject('$http', '$parse')
class SomeService {
constructor(
$http: angular.IHttpService,
private $$parse: angular.IParseService
) {
// do stuff with $http and $$parse;
}
public someMethod(anArg: number): boolean {
// do some stuff with this.$$parse();
}
}
@controller('ngModuleName', 'SomeController')
class SomeController {
constructor(
@inject('$scope') $scope: angular.IScope,
@inject('$parse') private $$parse: angular.IParseService
) {
// do stuff with $scope and $$parse;
}
public someMethod(anArg: number): boolean {
// do some stuff with this.$$parse();
}
}
Static class members of directive controller are used as config directive config.
@directive('ngModuleName', 'atSomeDirective')
class SomeDirectiveController {
public static controllerAs: 'someDirectiveCtrl';
public static templateUrl: string = '/partials/some-directive.html';
public static link: angular.IDirectiveLinkFn = (scope, element, attrs, ctrl: SomeDirectiveController) => {
ctrl.init(attrs.atSomeDirective);
};
constructor(
@inject('$scope') private $$scope: angular.IScope,
@inject('$parse') private $$parse: angular.IParseService
) {
// do stuff with $$scope and $$parse;
}
public init(anArg: string): boolean {
// do some stuff with this.$$parse and this.$$scope
}
}
If you use constructors/classes to create common entities a @classFactory can be useful. It passes constructor as angular service and attaches @inject's to it's prototype with leading '$$'.
@classFactory('test', 'Headers')
@inject('$http', '$parse')
class Headers {
public accept: string;
private $$http: angular.IHttpService;
private $$parse: angular.IParseService;
constructor() {
this.accept = this.$$parse('defaults.headers.common.Accept')(this.$$http);
}
}
and the somewhere else:
…
constructor(
@inject('Headers') Headers: Headers
) {
this.headers = new Headers();
}
…
This one is somehow similar to @classFactory, but it also encapsulates magic powers of angular $resource. $resource configs are gathered from static class members (just like in @directive decorator).
@resource('test', 'UserResource')
@inject('$http', '$parse')
class UserResource extends at.Resource {
public static url: string = '/fake/url';
public name: string;
public age: number;
private $$http: angular.IHttpService;
private $$parse: angular.IParseService;
constructor(model?: ITestModel) {
if (model) {
this.name = model.name;
this.age = model.age;
}
}
public getLabel(): string {
return `${ this.name }-${ String(this.age) }`;
}
}