こんにちは、平奥です!
はじめて TECHSCORE の記事を書いて約1年。気が付くといつの間にかフロントエンドエンジニアになっていました。時の流れは早いものです。業務で使用している AngularJS ですが、もうすぐ Angular 2 も出てきますよね。
Angular 2 は現在 RC4 までリリースされました。正式バージョンも今年中には出てくるのかなと期待しています。が、すでに AngularJS を使っている人間からすれば、Angular 2 は互換性がほとんどないので、改修が大変です。
AngularJS のままの運用でもセキュリティーなどの問題が出てきて、否応なしに Angular 2 へ移行しなくてはならないのかなと頭を抱えている人も多いはずです。しかし Angular 2 が出るまで、指をくわえて待っている必要もありません。
AngularJS は来たる Angular 2 に備えて、少しでも簡単に移行できるよう新しい機能を準備してくれています。
そこで今回は AngularJS 1.5 で新たに追加された機能を通して、Angular 2 に移行しやすいコーディング方法を紹介していきたいと思います。
まずは Angular 2 で起こることを確認
ここで Angular 2 で起こることを抜粋して確認します。
- $scope や Controller がなくなる
- 双方向データバインディングが廃止される
- TypeScript/ES6 が採用される
これを聞いたときはホントびっくりしました。TypeScript や ES6 が採用されるのはわかるのですが、$scope や Controller がなくなるってどうなるの?って思いました。
じゃあ Angular 2 に向けて何ができるか??
- $scope は使わない
- 双方向データバインディングをできるだけ使わないようにする
- TypeScript や ES6 でコーディング
そうですね。当たり前ですが、なくなってしまうものは使わなければいいんです。AngularJS 1.5 ではこれに対応するための新たな機能が追加されています。どういう風に対応すればいいか説明していきたいと思います。
コンポーネントディレクティブ定義
これによって、Angular 2 のコンポーネントのようなコンポーネントディレクティブが使えるようになりました。そもそも Angular 2 のコンポーネントって何?って感じですよね。詳しい説明は割愛しますが、 directive に類似したもので要素を定義するものとなります。例えば、以下の AngularJS のコードは、
1 2 3 4 5 6 7 8 9 10 11 12 |
myModule.directive('myComponent', { template: '<h1>Hello {{getFullName()}}</h1>', scope: { firstName: '=', lastName: '=' }, controller:[$scope, function($scope) { $scope.getFullName = function() { return $scope.firstName + ' ' + $scope.lastName; }; } }); |
Angular 2 では、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import {Component, Input} from 'angular2/core' @Component({ selector: 'child-component', template: ` <h1>Hello {{getFullName()}}</h1> ` }) export class ChildComponent { @Input() firstName: string; @Input() lastName: string; getFullName() { return this.firstName + ' ' + this.lastName; } } |
と、このようなソースになります。
AngularJS 1.5 のコンポーネントディレクティブ定義では、Angular 2 のコンポーネントにだいぶ近いかたちでコーディングすることができます。ソースは以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
myModule.component('myComponent', { template: '<h1>Hello {{ $ctrl.getFullName() }}</h1>', bindings: { firstName: '<', lastName: '<' }, controller: function() { this.getFullName = function() { return this.firstName + ' ' + this.lastName; }; } }); |
今まで $scope を使っていたところを bindings を使って定義することができます。これにより Controller で $scope を参照しなくても済むようになりました。また '='ではなく '<' を使用することにより単方向バインディングを実現することも可能となりました。これにより双方向バインディングを使わなくて済むようになりました。bindings の firstName や lastName には this を使用して参照することとなります。 Angular 2 のソースと見比べていただいてもわかるように類似していますので、移行が楽になるだろうと思います。
コンポーネントディレクティブ定義。苦手なこともある。
- DOM操作、イベントリスナー等を使っているディレクティブ(コンポーネントは link や compile が使えない。)
- priority、terminal、multi-element などの進歩的なディレクティブ定義を使用する時
- element よりも attribute や CSS class を使ったディレクティブが欲しい時
※ priority (ディレクティブの実行順を制御するプロパティ)
terminal ( terminal を true にした directive より priority が小さい directive は実行されないというような制御を行うプロパティ)
multi-element (ひとつのディレクティブで複数の DOM 要素を指定するプロパティ)
ですので、コンポーネントディレクティブ定義を使用するときは上記に該当しない単純なディレクティブを作成するときに有効な手段であるということになります。
コンポーネントディレクティブ定義は使えないけど、$scope は排除したいよ!そんな時は ControllerAs で
link や Compile を使っているので、コンポーネントディレクティブが使えない。なんとか Angular 2 に向けての改善はできないか。そういう時は ControllerAs を使えば $scope がなくなり移行しやすいソースになります。以下サンプルソースです。
ディレクティブのサンプルソースです。
1 2 3 4 5 6 7 8 9 10 11 |
app.directive("greeting", function() { return { restrict: "E", bindToController: { name: "=", }, template: `<h1>{{ctrl.sayHello()}}!</h1>`, controller: GreetingCtrl, controllerAs: "ctrl" }; }); |
コントローラはこうなります。
1 2 3 4 5 |
app.controller("GreetingCtrl", function() { this.sayHello = function() { return "Hello!! " + this.name; } } |
ControllerAs を使うと Contoroller の alias が指定できるようになります。この alias を使用することにより、$scope を使わずに Controller のプロパティーやメソッドが使えます。また bindToController を使用することによって今まで $scope を使って分離スコープを指定していましたが、$scopeを使わずに指定できるようになりました。ちなみに bindToController は AngularJS 1.4 新規機能です。
ここで実際のソースで確認!いろんな種類のバインディング
AngularJS は双方向バインディングで、Angular 2 では単方向バインディングになります。ワンタイムバインディングというものもありました。ここでは実際に動作するサンプルソースを記載しておきます。それぞれのバインディングについて動作を確認いただければと思います。
双方向バインディング
双方向バインディングは、親を変更すると子も変更され、子を変更すると親も変更されます。
単方向バインディング
単方向バインディングは、親を変更すると子も変更されますが、子の変更は親には影響を与えません。
ワンタイムバインディング
ワンタイムバインディングはその名のとおり、ワンタイム、すなわち一回だけの更新です。一度更新されたあとは親、子のどちらの値を変更しても互いに影響は与えません。
※ ブラウザによっては動作しない場合がございます。動作しない場合はお手数ですが、他のブラウザにて確認してください。
まとめ
Angular 2 は以前からガラッと変わって互換性がないというようなことが噂されていました。実際に互換性のない、ほぼリプレイス作業が必要なくらいの変更になりました。しかし、その変更を補うべく、AngularJS のバージョンアップで様々な移行をよりよくする機能が搭載されています。これからも AngularJS のバージョンアップは行われます。Angular 2 への移行の手助けとなるような機能がさらに搭載されると思います。バージョンアップした時には、そのバージョンアップで搭載された機能を確認し、利用することが Angular 2 への移行を簡単にする近道だと思います。ですので AngularJS を使われているみなさま、バージョンアップがされた時には、一緒に新規機能の確認を楽しみましょう!