angular.haxe
angular.haxe is a toolset for integration of angular.js in haxe applications. It tries to combine angular.js with the type safety of haxe as much as possible. The angular API is fully typed and haxe macros extend the api to support dependency injection based on types instead of unsafe strings.
It's currently incomplete, feel free to add pull requests or become a contributor.
Example of angular.haxe dependency injection
// a regular haxe modelclass Config { public var appName = "News App"; public function new () {}} class Main{ static function main () { // controller definition, the parameter types determine // which dependencies needs to be injected. function appController (scope:Scope, config:Config) { trace("appController initialized"); scope{ appName : config}); }; // module definition var module = Angular[]) // no need give the factory a name, // the link is created by the types appController); }}
Angular-Haxe {{data.appName}}
See Sample 2 for a slightly larger working example. The generating js file for this example can be found here.
angular.haxe vs angular.js
here are same snippets which highlight differences of angular.haxe vs pure angular.js
Factory / Service registration with dependencies
Factory registration with js.
{ // do something with timeout and location} // register as factoryangular
In angular.haxe dependency injection in general is based on the type to achieve more type safety. This type gets translated into a string at compile time, e.g. my.pack.MyService becomes "my.pack.MyService". This translation is done through macros which run at compile time and convert the abstract syntax tree in such a way that the generated code is very similar to the js code.
import angularimport angularimport angular class MyService { public function new (timeout:Timeout, location:Location) { // do something with timeout and location }} // register as factoryAngular[])
This generated js code looks similar to the next snippet.
.factory("MyService", ["$timeout", "$location", function (a1, a2) { return a1a2 });
You may wonder why a type of a core angular services like Timeout are translated to $timeout instead of "angular.service.Timeout". The reason for this is that the core types are annotated with speacial metadata like @:injectionName("$timeout"). Types with this metadata are handled in special way inside of macros like factory, the value inside of this metadata is used instead of the full qualified class name.
Controller
Controller in angular.js
angular
The same logic in haxe
Angular[]) functionmyService:MyService) { // do something })
Directives
Directive in angular.js
angular ;
While you can define the directive in the same way (very dynamic), you can also use the class angular.support.DirectiveBuilder
to create a directive. This class is a DSL to build a directive step by step. Note that the link function requires all five supported parameters instead of just the 2 like in the js version. But you can also write function (scope:Scope, e:Element, _,_,_) {
if you don't require the last parameters.
Angular[]) DirectiveBuilder e:Element, a:Attributes, c:Controller, t:TranscludeFn) { scope"Jeff"); }) );
Advanced Topics
Typed Scope
import angularimport angular typedef AppScope = { data : { firstName : String, lastName : String }}; class Main{ static function main () { function appController (t:TypedScope<AppScope>) { t= { lastName : "tom", firstName : "timmy" }; } var module = Angular[]) appController); }}
Using the same type for multiple services
In order to use the same type for multiple services typedefs (aliases) can be used. This is possible because this library uses macros to inspect the injected types at compilation time and not at runtime.
import angularimport angular typedef Url = String;typedef Title = String;typedef Description = String; typedef AppScope = { data : { url : String, title : String, description : String }}; class Main{ static function main () { var module = Angular[]) function ():Url return "https://github.com/frabbit/angular.haxe") function ():Title return "angular.haxe") function ():Description return "Some words about angular.haxe...") functionurl:Url, title : Title, desc:Description) { s= { url : url, title : title, description : desc }; }); }}
As an alternative the special Const
type parameter can be used to distinguish between different Strings by using constant string type parameters.
import angularimport angular typedef CustomString<Const> = String; typedef AppScope = { data : { url : String, title : String, description : String }}; class Main{ static function main () { var module = Angular[]) function ():CustomString<"url"> return "https://github.com/frabbit/angular.haxe") function ():CustomString<"title"> return "angular.haxe") function ():CustomString<"desc"> return "Some words about angular.haxe...") functionurl:CustomString<"url">, title : CustomString<"title">, desc:CustomString<"desc">) { s= { url : url, title : title, description : desc }; }); }}
Functions can be services and are identified by signature
import angularimport angular typedef Title = String; typedef AppScope = { data : { title : String }}; class Main{ static function main () { var module = Angular[]) function ():Void->Title return function () return "angular.haxe") function ():Title->String return functionreturn "!!! " + t + " !!!") functiongetTitle:Void->Title, format:Title->String) { s= { title : format}; }); }}
Bundles are auto-composed injectable structures based on other services
package ; import angularimport angular typedef Bundle = { x : String, y : Int}; typedef AppScope = { data : { title : String }}; class Main{ static function main () { var module = Angular[]) function () return 5) function () return "times") ( _ : Bundle ) ) functionbundle:Bundle) { s= { title : bundle+ " " + bundle}; }); }}
Technically .bundle( ( _ : Bundle ) )
this is just a shortcut for the following code. It becomes really useful for larger bundles with a lot of fields.
functiony:Int):Bundle { return { x : x, y : y}})