After using this macro for 2 days, I don't recommend it anymore. When I write code in that way, I can't stop thinking "what the js code it will generate? Is it correct"? It's too tired. And also found small errors it introduced, which may be fixed, but we need more rules for coding.
So I recommend the classic way of writing angularjs code, as shown on here.
This is a haxe macro which can let us writing augularjs controllers in class structure(fields and methds).
Actually, there is no extra macro needed to develop angularjs applications with haxe, you can see a demo from cambiata:
https://github.com/cambiata/Haxe-AngularJS-test/blob/master/src/site/MainController.hx
But the code may be improved:
- I don't want to declare a
typedef
for the scope argument, to repeat myself to declare those fields and functions - I want to organise my code with class structure(fields and classes), it will be cleaner and benefit from the IDE (outline view)
- I don't want to write the "init" function each time
So I asked a question here: http://stackoverflow.com/questions/14397460/is-it-possible-to-let-angularjs-work-with-prototype-methods-and-variables
Since there is no good answers, I have to do it myself, with haxe. After 4 days of work, this project is born. I really appreciate back2dos and his great tink_macros library, he gave me so much help, and also Simon and cambiata, and Atry. This project is pretty simple, but it shows me the power of haxe, that I think I can use haxe in my project from now on.
With my "AngularSupport" macro, I can write angularjs controller this way:
import freewind.AngularSupport;
class MyCtrl implements Public, implements AngularSupport {
@AngularSupport({inject:['$scope', '$http'], scope:'$scope'})
function new(scope:Dynamic, http:Dynamic) {
this.http = http;
// don't need to assign "scope" to anything
}
var http:Dynamic;
var name = "Freewind";
function hello() {
js.Lib.alert(name);
}
}
It will generate haxe code to:
import freewind.AngularSupport;
class MyCtrl implements Public, implements AngularSupport {
public static function __init__() {
js.Lib.eval("MyCtrl.$inject = ['$scope', '$http'];");
}
function new(scope:Dynamic, http:Dynamic) {
this.http = http;
// don't need to assign "scope" to anything
scope.http = Reflect.setField(scope, 'http', Reflect.field(this, 'http'));
scope.name = Reflect.setField(scope, 'name', Reflect.field(this, 'name'));
scope.hello = angular.bind(scope, this.hello);
}
var http:Dynamic;
var name = "Freewind";
function hello() {
js.Lib.alert(name);
}
}
Which can generate correct javascript code for angularjs.
- The controller must implements "AngularSupport" interface
- Put a metadata
@AngularSupport({inject:['$scope', '$http'], scope:'$scope'})
on the constructor, which is functionnew
- Don't assign the passing
scope
to any fields - Static variables and functions won't be added to 'scope'
- Private variables won't be added to 'scope'
The 5th rule is important for nesting controllers. If I will use some data from parent's scope, that I need it to be private, then I can just use it(from parent), without assign it to current scope with a new value.
- Use nightly-build haxe, since it requires latest macro api. For me, I use the build r5894, you can find download links here:http://haxe.org/download/manual_install#svn-builds
- It requires lib "tink_macros", but the version "1.2.1" from haxelib is not new enough. You can use the code I included in this project (src/tink), or clone from https://github.com/back2dos/tinkerbell
Welcome trying and improving it :)