念の為前書きですが、今回の題材は、私が調べてもベストプラクティスが見つからなかった部分を題材にしておりますので、
もしもっと良い方法があった場合ご教示いただければ、という前提で書かせていただきます。
解決したいこと(困りごと)
- カスタムディレクティブの可読性が悪い
- TypeScriptでのベストプラクティスの例が少ない(or 無い)
- classとか有効活用したい
まず...
困り気味なソースを見てみましょう。
angular.module('fooApp')
.directive('fooDirective', function () {
return: {
restrict: 'E',
link: function ($scope, $element, $attrs) {
$scope.foo = 'foo';
$scope.bar = 'bar';
xxxx = () => {
console.log($scope.foo, $scope.bar);
};
$element.on('click', function () {
xxxx($scope.foo, $scope.bar);
});
}
}
})
;
上記の場合、ディレクティブが増えれば増えるほど、
複雑な処理をすればするほど可読性が悪くなってきます。
あといちいち「$scope」とか書くのめんどうくさい!
つぎに...
改善したソースを見てみましょう。
class FooDirective {
restrict: string = 'E';
controller: string = 'FooCtrl as c'
}
class FooController {
public foo: string = 'foo';
public bar: string = 'bar';
// 個人的なポリシーとしてjQueryオブジェクト以外に
// $を付けたくないので、別の名前のメンバ変数を用意しています
scope: ng.IScope;
attrs: any;
constructor (
private $element: ng.IAugmentedJQuery,
$scope: ng.IScope,
$attrs: any
) {
this.scope = $scope;
this.attrs = $attrs;
this.bindEvents();
}
bindEvents () : void {
this.$element.on('click', () => {
this.xxxx();
});
}
xxxx () : void {
console.log(this.foo + this.bar);
}
}
angular.module('fooApp')
.controller('fooCtrl', FooController)
.directive('fooDirective', () => new FooDirective())
;
ディレクティブ用のコントローラーをクラスとして明記しています。
もちろん、クラスを使っているので、継承も自由にできます。
似たようなディレクティブだけど、少し性質を変えたい時とかこの書き方だと大分いい!
ディレクティブを定義している部分を見れば、どのコントローラーと対になっているかもわかるので、
私としては一番よかった書き方になります。
「Controller as」の有効利用
AngularJS + TypeScriptでは、「Controller as」を使う、というお作法があります。
これはカスタムディレクティブでも有効で、
クラス内でのthisが$scopeに相当するため、可読性の向上の助けになるかと思います。
$scope.fn = () => {
// ...
};
とか書いていたものは
public fn () : void {
// ...
}
と、なんか素敵に書く事ができます。
最後に
私自身まだまだこの構成でプロダクトを作りはじめたばかりのため、
100%信じていただくより、いち参考資料として見ていただければ幸いです。
今後コントローラーではなくディレクティブをたくさん使ってねー
みたいな仕様になりそうなので、いそいそと書かせていただきました。
ありがとうございました!