ng-annotation
angular wrapper based on es7 annotations
=======================
Ng-annotations is a small javascript library that helps to produce more structured angular applications using es6 classes and es7 decorators.
This library was build with webpack in mind but should works well with the other transpilers/javascript supersets like babel or typescript (with es7 and es6 advanced features)
Index:
Installation
npm
npm install --save ng-annotations
Bower
bower install --save ng-annotations
Basic Usage
all examples in this repo and below use the babel-core library as transpiler you're free to use any other if it supports the es7 decorator feature.
webpack
a configuration example is available in the webpack dev config
; @@ { /*do something*/ }
es6 files
a configuration example is available in the gruntfile
const controller inject = ngAnnotations; @ { /*do something*/ }
Informations
All the examples below will show you the webpack way.
However, an implementation of the angular todolist with the basic es6 syntax is available in the example/es6 folder
How it works:
all component annotations add 3 properties and 1 method to the given class
$type
: String. the component type (controller, config, service...). Used by theautodeclare
method.
$name
: String. the component name used by angular. Used by theautodeclare
method. Useful if you want to use the import system with the dependency injection system. With this method you'll avoid all hypothetical naming issues.
/*file1.js*/; @ {} /*file2.js*/; // import {$name as myService} from './file1'; //before 0.1.6; @@ {}
$component
: Object. the object/function used by angular, can be different than the original class (function wrap). Used by theautodeclare
method.
autodeclare
: Function(ngModule). declares the current component to angular. (replaces the traditionalangular.module('...').controller('name', fn)
)
the ngModule parameter can be a string (angular module name) or an angular module instance.
/*autodeclare way*/;; var app = angular;// useful if you wanna use the import system with the module dependency injection system.; myService myController; /*alternative*/;; var app = angular;; // useful if you wanna use the import system with the module dependency injection system. app;app; /*without import*/; @ {} MyService;
Available annotations
Utils
@inject
The inject annotation replaces the classical array syntax for declare a dependency injection
Basically, it will feed the $inject property with the list of dependencies
type: function
target: class and methods
Params:
- depsToInject: String|String[]|Component[]|Component. component(s) to inject
- ...otherDeps: (Optional) ...Strings.
Usage:
;; @@ // could be @inject(['$http','$q',myFactory]) { thishttp = http; thispromise = $q; thisfactory = factory; } do /*do something*/
Note:
The implicit dependency injection syntax is also available but shouldn't be used because of minification issues.
Usage:
; @ { thishttp = $http; thispromise = $q; } do /*do something*/
@autobind
The autobind annotation gives the possibility to bind methods to its current context.
similar to object.method.bind(object)
type: statement
target: method only
Usage:
; @@ { thistimeout = timeout; this; } @autobind { console; this; }
@attach
The attach annotation provides a shortcut to bind references across components and keep them safe.
type: function
target: attributes and methods
Params:
- source String|Component. source component
- "this" will target the current component
- path: (Optional) String. path toward the property
- split with dots.
obj.otherObj.myProperty
- split with dots.
Usage:
// factories/user.js; @@ { thisnestedproperty = 5; } connectedUsers = 0; thisusers = ; { this$http } // controller/user.js;; @@ @ // this.userlist will refers to UserFactory.users userlist; @ randomProperty; @ // same as this.reload = factory.load.bind(factory); reload; { thisusers = ; // update the UserFactory.users property, the reference is kept. }
Note:
binded target can be a function, a primitive or an object
Warning:
The binding occurs after the constructor calling, so you can't use the property at this step. use the controller parameters instead.
@conceal
the conceal decorator provides a way to declare the annotated properties as private
type: statement
target: methods and attributes
Usage:
; @@ @conceal @ $http @conceal datas = ; { thisdatas = 123; } { return this; } @conceal {}
Components
@controller
declare the given class as an angular controller
type: function
Params:
- name: (Optional) String. angular controller name, by default the decorator will take the class name.
Usage:
; @ prop = 0;
Note:
With this syntax you should always use the controllerAs option and forget $scope (except in certain cases like $watch or $on usages).
Usage:
html head body section(ng-controller="HelloWorld as HW") {{HW.prop}} script(src="app.js")
@service
declare the given class as an angular service
type: function
Params:
- name: (Optional) String. angular service name, by default the decorator will take the class name.
Usage:
; @ { return 100 * Math|0 }
@provider
declare the given class as an angular provider
like the native angular provider you must implement a$get
.
type: function
Params:
- name: (Optional) String. angular provider name, by default the decorator will take the class name.
Usage:
; @ @ {}
@factory
declare the given class as an angular factory
type: function
Params:
- name: (Optional) String. angular factory name, by default the decorator will take the class name.
Usage:
; @ items; { thisitems = ; }
by default the decorator return an instance of the factory class to angular so the example above is similar to the following code
angular
You can change this behaviour by defining an
$expose
method
; @ items; @autobind { return thisitems; } @autobind { thisitems = list; } return load: thisload get: thisget angular
@directive
declare the given class as an angular directive
type: function
Params:
- name: (Optional) String. angular directive name, by default the decorator will take the class name.
Usage:
; @ restrict = 'A'; scope = {}; { console;; }
@animation
declare the given class as an angular animation
type: function
Params:
- selector: String. css selector.
Usage:
; @ { elem; /*do something*/ } { elem; /*do something*/ }
@config
declare the given class as an angular config
type: function
Usage:
; @@ { thisroute = routeProvider; this; } { thisroute }
@run
declare the given class as an angular run
type: function
Usage:
; @@ { thisfact = myFactory; this; } { thisfact; }
@filter
declare the given class as an angular filter
type: function
Params:
- properties: (Optional) Object|String. angular filter properties. contains the name and the stateful attribute
- name: String. angular filter name, by default the decorator will take the class name.
- stateful: Boolean. default false
Usage:
The decorated filter is slightly different than the original. to make it work you need to implement a
$filter
method. This is the method used by angular.
; @ { return val0 + val; } return this;
Note:
If you need to write a stateful filter, you must give a literal objet as parameter to the filter decorator
//inspired by https://docs.angularjs.org/guide/filter; @@ @ decorator; return thisdecorator + input + thisdecorator;
@decorator
provides a way to decorate an existing angular element
type: function
Params:
- name: String. angular element's name to decorate.
Usage:
; @@ { /*decoration*/ }
by default the decorator return an instance of $delegate so the example above is similar to the following code
angular
You can change this behaviour by defining an
$decorate
method
; @@ //@attach('$delegate') //$delegate; { console; } //this.$delegate.sayHello = () => this.sayHello(); //return this.$delegate; return this; angular
Wrappers
the Value and Constant components can't be replaced by a class.
In order to simplify their declaration two wrappers are available.
constant
Params:
- name: String. constant name.
- value: Mix. constant value.
Usage:
; 'name' 'a constant';
value
Params:
- name: String. value name.
- value: Mix. value value.
Usage:
; 'name' 'a value';
Composites
The composites decorators aren't simple angular component wrappers like above, they implement new concepts on top of Angular 1.
@component
This decorator declares the given class as a controller and creates an associated directive
With the emergence of the new components oriented frameworks like react or angular 2, the application structures changed drastically. Most of the time, when we create a directive we want also create a controller with its own logic, however create 2 files for 2 lines of code each is a waste of time. The following decorator combine a controller and a directive in the way of the angular2's @component.
type: function
Params:
- options: (Mandatory) Object. component options.
- selector: (Mandatory) String. directive's name
- alias: (Optional) String. controllerAs option, defaults to the selector value
- type: (Optional) String. directive's restrict option, defaults to
E
- ioProps: (Optional) Object. the scope properties, all props are bind with the
=
operator (two way binding) - template: (Optional) Any. directive's template option
- templateUrl: (Optional) Any. directive's templateUrl option
- transclude: (Optional) Boolean. directive's transclude option
- lifecycle: (Optional) Object array of callbacks, the available hooks are
compile
,prelink
andpostlink
the component decorator injects a $ioProps property to the working class. It contains the scope properties
Usage:
; @@ { console; }
Modify and build
npm install webpack-dev-server -g
npm install webpack
npm install
Build dist version: npm run build
Build es6 example: npm run es6
Start the dev server: npm run dev
then go to http://localhost:8080/webpack-dev-server/