ng-metasys
A metadata framework for AngularJS 1.5.x that makes default angular metadata system working clearly with ES2015/Typescript module system.
This framework has no aim to emulate Angular 2 DI system. Instead, it considers Angular 1.5.x features and offers an architecture that is convenient for it.
Installation
$ npm install ng-metasys --save
Usage
bootstrap
Everything starts with bootstrap
function. If you choose the
ng-metasys
package, you should understand, that you will not
be able to use angular auto-bootstrapping with ngApp
directive.
The bootstrap function has to be placed at the enter point of
your application. It receives a class marked with @Module
decorator and bootstraps it.
Bootstrap function signature is:
Your application entry point can look like this.
;; ;
@Module
Module is the fundamental Angular entity that encapsulates one structural unit of the application. It contains all submodules, declarations and configurations of this unit.
Default Angular module initialization is far away from
ES2015/Typescript module system. So, ng-metasys
offers following
initialization through separate module class, that contains
@Module
decorator with information about declarations
and module import and class methods that implements module
configuration.
More about Angular Module
@Module
has following signature:
Your app.module.js
can look like following:
;;;; @ @Value static value = 1; @Constant static constant = 'two'; @Config @ static {} @Run static {}
This code is equivalent to the following:
angular value'value' 1 ;
@Component
Component is the one more fundamental entity that encapsulates view and behavior of single visual part of application.
More about Angular Component.
@Component
signature is simple:
@Component
can be expanded by additional functional like ng-transclude
using the extension decorators like Transclude
.
Your app.component.js
can look like following:
; @@ @ $router; @ onClick; $http; $q; { this$http = $http; this$q = $q; }
Which is an equivalent to the following code:
angular
@Directive
Directive controls behavior of HTML elements marked with certain attribute or class.
More about Angular Directive.
@Directive
signature is equal to @Component
:
If directive should be applied to the element with attribute, it selector has to look like that:
@
If directive should be applied to some class, it has to be following:
@
If directive should be applied to some comment, it has to be following:
@
Unlike component, directive can contain a static method marked with
@Link
decorator. It creates a directive link function that allow
to control HTML elements directly.
Your some.directive.js
can look like following:
; @ @Link static {} @ close; $q; { this$q = $q; }
Which is equivalent to the following code:
angular ;
@Service
Injectable provider that implements concept of singletone data service.
More: Angular Service.
@Service
does not have signature. Just place a @Service
mark above
the class to make it Angular Service.
Your some.service.js
can look like following.
; @Service $http; { this$http = $http; }
Which is equivalent to the following code:
angular ;
@Factory
Factory is a function shared in AngularJS. To implement it using
@Factory
mark just create a class with static method $get
.
More: Angular Factory
Your file some.factory.js
can look like following:
; @Factory @ static {}
Which is equivalent to the following code:
angular ;
@Provider
Basic structure for @Service
and @Fabric
. To implement @Provider
you should create a class with the method $get
.
Your file some.provider.js
can look like following:
; @Provider @ {}
Which is an equivalent to the following code:
angular ;
@Filter
Filter in AngularJS allows to process text data with certain pattern
defined by filter. To implement it using @Filter
mark just create a
class with static method execute
.
Your some.filter.js
can look like following:
; @Filter @ static { return {} }
Which is an equivalent to the following code:
angular ;
Extensions metadata
Extensions metadata is the set of decorators that can be used in different AngularJS elements.
@Inject
@Inject
allows to inject various providers into components, directives,
other providers etc. @Inject
can be used in following ways:
- Inject into constructor parameter:
;; @Service { this$http = $http; this$http; }
Equivalent code:
angular ;
- Inject into constructor:
;; @Service@ {}
It allows using injected data in the constructor. Equivalent code:
angular
- Inject into methods:
; @ @Config @ {}
It allows injecting data into the class method. Usually this method is used by Angular as a function, and the other class parts are ignored. Equivalent code:
angular
@Bind
Bind
is used in components and directives as elements of bindings
and
bindToController
sections respectively. So, if you have following code:
; @ @ myBindingProperty;
It is an equivalent to the following construction:
angular ;
For the bindToController
block rules are equal considering the difference between
bindToController
and bindings
.
@Transclude
Transclude allows including HTML code inside the component/directive host
tag to the resulting HTML template. To implement transclusion just add
the @Trasnsclude
mark to the component or directive and send to it
an object with transclusion rules described in
Angular NgTransclude
article.
;@@
It is an equivalent to the following code:
angular ;
How to get original AngularJS metadata from decorated declaration
When you need to use something like angular-ui-bootstrap
and it's
service $uibModal
, or angular-ui-router
of version less than
1.0.0
, you need to get original AngularJS metadata from decorated
declarations.
To accomplish this goal ng-metasys
contains two main resources:
modules
- is a instance ofMap
that gets you access to a module list where you can find out the AngularJS module existence or get an instance of the module you need.modules
property is a simple ES2015Map
object with module names as keys and module instances as values.getMetadata
- is a function that allows to get an AngularJS metadata. Just send specified declaration togetMetadata
and you will get all metadata it contains.
So, for the simple component:
; @@ @ $router; @ onClick;
You can get following metadata:
; ;
Matchers
If you want to know what the ng-metasys
element is represented by
specific declaration, you can use the one of the matcher functions:
isComponent
,isDirective
,isFactory
,isFilter
,isProvider
,isService
; @ {} ;
Plug-in system
This package implements only basic AngularJS functional. But there are many additional packages extending AngularJS core - may be your own, - and they have to be implemented. For such purposes there is plug-in system that allows to implement own decorator and include it to the common bootstrapping flow.
Plug-in has following structure:
<name>
├── <name>-bootstrap.js
├── <name>-decorator.js
├── <name>-token.js
├── <name>-reflection.js
├── index.js
File <name>-token.js
defines the token where the metadata will
be stored. Token should be a Symbol
to avoid any possible
collision. You also can define the permanent token here if you
want your data to be accessible through the custom getMetadata
function.
// my-token.jsconst token = Symbol'my';const permanentToken = Symbol'permanent:my';
File <name>-decorator
describes a decorator storing metadata of
the target class. Metadata should be stored using Reflect
from reflect-metadata
package.
// my-decorator.jsconst My = Reflect; ;
File <name>-bootstrap.js
contains bootstrap function being loaded
during the bootstrapping process. To add the plug-in bootstrapping
function to the ng-metasys
flow, it should be put into
registerPlugin
function that can be imported from
ng-metasys
.
Bootstrap function receives angular module and the declaration belonging to it. First thing you should do in your bootstrap function is to check if this declaration is the declaration you saved data for. Then just call necessary module function and init the data you have.
If you want data to be accessible through getMetadata
function
you have to register your permanent token and metadata using
defineMetadata
function from the ng-metasys
. Then it
will be accessible from your custom getMetadata
function.
;; const myBootstrap = { if !Reflect return; const metadata = Reflect; ngModule; //register metadata with permanent token ; }; ;
If you have injectables written in terms of ng-metasys
to
be injected into ngModule
functions, pass them in array to
the registerPlugin
as second argument. You can get their names
as third and following arguments of your bootstrap function.
Note: injectable should be initialized in current module or
in it's dependencies written in terms of ng-metasys
.
;;;; const myBootstrap = { if !Reflect return; ngModule; }; ;
File <name>-reflection.js
defines your custom getMetadata
function. It is optional - only if you want to get access to the
metadata of your plug-in. To get metadata from this function use
getPluginMetadata
from ng-metasys
and your permanent
token.
;; const getMyMetadata = ; ;
File index.js
exports your decorator and custom getMetadata
function (if any).
;;
License
Information about license can be found here.