An approach to using ES6 classes in Angular JS 1.x with Typescript
npm install @ioffice/angular-ts

This library provides ngRegister, a modified version of Michael Browmley's [register.js][1].
angular-ts allows us to declare classes and register them as angular components. Here is a summary
``typescript
import { ngRegister } from 'angular-ts';
class MyAngularComponent {
constructor(dependency1, dependency2) {
this.dependency1 = dependency1;
this.dependency2 = dependency2;
// stuff happens here
}
someMethods() {
this.dependency1.doThatThing();
this.dependency2.doThatOtherThing();
// more stuff here
}
}
MyAngularComponent.$inject = ['dependency1', 'dependency2'];
ngRegister('app')
.controller('MyController', MyAngularComponent)
.service('myService', MyAngularComponent1)
.provider('myOtherService', MyAngularComponent2)
.factory('myFactory', MyAngularComponent3)
.directive('myDirective', MyAngularComponent4);
`
or if you prefer to use the dependencies without declaring them you may use the inject function.
`typescript
import { ngRegister, inject } from 'angular-ts';
class MyAngularComponent {
constructor(...args) {
inject(this, args);
// stuff happens here
}
someMethods() {
this.dependency1.doThatThing();
this.dependency2.doThatOtherThing();
// more stuff here
}
}
inject(MyAngularComponent, ['dependency1', 'dependency2']);
ngRegister('app')
.controller('MyController', MyAngularComponent)
.service('myService', MyAngularComponent1)
.provider('myOtherService', MyAngularComponent2)
.factory('myFactory', MyAngularComponent3)
.directive('myDirective', MyAngularComponent4);
`
If you are using the experimentalDecorators option in the typescript compiler you may wish toInject
use the decorator. This allows us to write the previous example as
`typescript
import { ngRegister, inject } from 'angular-ts';
@Inject(['dependency1', 'dependency2'])
class MyAngularComponent {
constructor(...args) {
inject(this, args);
// stuff happens here
}
someMethods() {
this.dependency1.doThatThing();
// more stuff here
}
}
ngRegister('app')
.controller('MyController', MyAngularComponent)
.service('myService', MyAngularComponent1)
.provider('myOtherService', MyAngularComponent2)
.factory('myFactory', MyAngularComponent3)
.directive('myDirective', MyAngularComponent4);
`
The angular-1.x directives usually have a lot of options that you can provide. At some point it can
get annoying writing something like
`typescript
import { Inject } from 'angular-ts';
@Inject(['a', 'b'])
class MyDirective {
// Directive options
template: string;
requires: string[];
// ... other directive options
// Injected Dependencies
a: any;
b: any;
constructor(...args: any[]) {
inject(this, args);
this.template = 'template goes here';
this.requires = ['other directives'];
// ...
// and so on ...
}
}
`
Instead, we may extend from Directive and skip declaring the directive options.
`typescript
import { Directive, Inject } from 'angular-ts';
@Inject(['a', 'b'])
class MyDirective extends Directive {
// Injected Dependencies
a: any;
b: any;
constructor(...args: any[]) {
super(args);
this.template = 'template goes here';
this.requires = ['other directives'];
// ...
// and so on ...
}
}
`
This tells the typescript compiler that the class already declares template, requires andDirective
all the other options that a directive provides. Note that all a does is call injectsuper
during initialization as it has been previously done, so do not forget to call the args
constructor with .
For other examples see example/js/ex-directive.js. One thing to mention here is thatcompile, link, preLink and postLink are optional methods. Please note however that ifpostLink and link are both declared then only the postLink method will be called. These two
methods should be one and the same so only declare one.
Angular 1.5 introduces components. These were made to make migration to Angular 2 a bit
easier. To migrate we can write components as follows:
`typescript
import {
Inject,
inject,
NgComponent,
NgOnInit,
NgPostLink,
} from 'angular-ts';
@NgComponent({
selector: 'ex-component',
template: '
constructor(...args: any[]) {
inject(this, args);
}
$onInit(): void {
this.$element.css('color', 'red');
}
$postLink(): void {
console.log('This is the postLink hook, analogous to the ngAfterViewInit and ngAfterContentInit hooks in Angular 2');
}
}
export {
ExComponent,
};
`
To register the component we don't have to provide the selector name since this is already defined
in the NgComponent decorator.
`typescript
import { ExComponent } from 'ExComponent'
ngRegister('app')
.component(ExComponent);
`
See
on the life cycle hooks.
If you need to make a component that is a Directive and extends from some other class you maymix
use the function provided by this library. For instance:
`typescript
import { Directive, Inject, mix } from 'angular-ts';
class OtherClass {
constructor(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
}
getA() {
return this.a;
}
}
@Inject([
'dep1',
'dep2',
// and so on ...
])
class SomeController extends mix(Directive, OtherClass) {
constructor(...args) {
super([Directive, args], [OtherClass, 1, 2, 3]);
}
doSomething() {
console.log('Calling OtherClass method: ', this.getA());
console.log('Using dependencies: ', this.dep1.somemethod);
}
}
`
NOTE: Do not use instanceof when using mix. Instead use the isinstance function provided by
the library.
#### inject(clazz: any, injectables: (string | any)[]): void
Can be used after a class declaration to inject its dependencies as well as inside the constructor
to attach the dependencies to an instance of the class.
`typescript
import { inject } from 'angular-ts';
class A {
constructor(...args: any[]) {
inject(this, args);
}
}
inject(A, ['a', 'b']);
`
Note that when using after the declaration we must provide the class object and not an instance as
we have done in the constructor.
#### Inject(args: string[]): Function
A decorator to replace using inject after the class declaration. This allows us to see the
dependencies that an angular component uses right in the class declaration.
`typescript
import { Inject, inject } from 'angular-ts';
@Inject(['a', 'b'])
class A {
constructor(...args: any[]) {
inject(this, args);
}
}
`
Utility class which provides the following interface:
`typescript`
interface Directive {
controller?: any;
controllerAs?: string;
bindToController?: boolean | Object;
multiElement?: boolean;
name?: string;
priority?: number;
replace?: boolean;
require?: string | string[] | {
[controller: string]: string;
};
restrict?: string;
scope?: boolean | Object;
template?: string | Function;
templateNamespace?: string;
templateUrl?: string | Function;
terminal?: boolean;
transclude?: boolean | string | {
[slot: string]: string;
};
compile?(templateElement: ng.IAugmentedJQuery, templateAttributes: ng.IAttributes, transclude?: ng.ITranscludeFunction): void;
link?(scope: ng.IScope, instanceElement: ng.IAugmentedJQuery, instanceAttributes: ng.IAttributes, controller: any, transclude: ng.ITranscludeFunction): void;
preLink?(scope: ng.IScope, instanceElement: ng.IAugmentedJQuery, instanceAttributes: ng.IAttributes, controller: any, transclude: ng.ITranscludeFunction): void;
postLink?(scope: ng.IScope, instanceElement: ng.IAugmentedJQuery, instanceAttributes: ng.IAttributes, controller: any, transclude: ng.ITranscludeFunction): void;
}
Any angular component extending from Directive will need to call super with the constructorsarguments.
`typescript
import { Directive, Inject } from 'angular-ts';
@Inject(['a', 'b'])
class A extends Directive {
constructor(...args: any[]) {
super(args);
}
}
`
#### ngRegister(appName: string, dependencies?: string[]): NgRegister
Provides a wrapper for angular.module, we can create a brand new angular module by providing theNgRegister
module dependencies or get the angular module by omitting them. This will return an instance of which provides all the methods an angular module has: controller, directive,service, etc. To obtain the non-wrapped angular module use the method module.
`typescript
import { ngRegister } from 'angular-ts';
const app = ngRegister('mymodule', [])
.controller('ctrl', Ctr)
.directive('dir', Dir)
// ...
.module();
`
#### mix(...mixins: any[]): typeof IMixin
Allows us to create a custom class which combines all the methods of the specified mixins.
`typescript
class A {
a: number;
constructor(a: number) {
this.a = a;
}
printA() { console.log(this.a); }
}
class B {
b: number;
constructor(b: number) {
this.b = b;
}
printB() { console.log(this.b); }
}
class C extends mix(A, B) {
c: number;
constructor(a: number, b: number, c: number) {
super([A, a], [B, b]);
this.c = c;
}
printC() { console.log('c'); }
}
const obj: C = new C(1, 2, 3);
obj.printA();
obj.printB();
obj.printC();
`
#### isinstance(object: any, classinfo: any): boolean
Used to check if an object is an instance of a given class. We may provide an array in the second
argument if we want to check if an object is an instance of any of classes in the array.
#### loadNgModule(callback: Function): any[],
Utility function to help lazy load angular modules. To use it first require the module with
webpacks bundle loader:
const lazyBundleCallback = require('bundle?lazy!./realative/path/to/angular/module');
Then on the router load it on a resolve, for instance:
.state('somestate', {
url: 'someurl/',
views: {...},
resolve: {
lazyLoadModule: loadNgModule(lazyBundleCallback),
}
});
You may call lazyLoadModule anything you want, this is just a function that will resolve.
Note: You will need to register ocLazyLoad` with the app in order for this to work.
[1]: https://github.com/michaelbromley/angular-es6