AngularJSをさわってみた ~入門編
こんにちは、エンジニアの藤野です。
スパイスワークスのエンジニアチームは基本サーバサイド開発がメインですが、
フロントエンドの新しい技術もさわってみよう、ということで以前から話題で気になっていた
「AngularJS」を少々さわってみたのでご紹介します。
AngularJSとは?
AngularJSとは、Googleが主体となって開発しているJavaScriptのフレームワークです。
昨今話題になっているJavaScriptのMVCフレームワークですが、
トレンドとしては他のフレームワークから群を抜いてこのAngularJSが話題になっているようです。
参考:人気上昇中のJavaScriptライブラリを調べてみた【2015年版】
厳密にはこのAngularJSは「MVW(Model-View-Whatever)」を謳っており、
WにあたるWhateverは「何でもあり!」という勢いです。
主な特徴としては以下のようなことが挙げられます。
- データバインディング
モデル(データ)とビュー(表示)を紐づけることによってユーザからのデータ入力を即時に表示に反映させることが可能となります。 - ディレクティブ
AngularJS独自のHTMLプロパティ(これを「ディレクティブ」といいます。)をHTMLタグに付与してDOMを操作します。 - テンプレートとしてのHTML
HTMLタグにAngularJS独自のディレクティブを付与することで従来のHTMLドキュメントをそのままテンプレートとして使用します。
AngularJSが読み込まれない場合でもそのまま通常のHTMLドキュメントとして表示されます。
では、実際にどのような感じで使うのか簡単に見てみましょう。
データバインディング
テキストボックスがあって、入力されるとターゲットとなるHTML要素内にその入力文字を反映させたい場合を考えてみましょう。
従来なら、jQuery辺りを使って入力ボックスのchangeイベントを検知して値を取得し、
ターゲットとなる要素の内容を書き換える、というような実装になるかと思います。
例えば以下のような感じでしょうか。
<input type="text" name="hoge" /> <div id="target"></div> <script type="text/javascript" src="/js/jquery.js"></script> <script type="text/javascript"> $("input[name=hoge]").change(function(){ $("#target").html($(this).val()); }); </script>
ちなみに、テキストボックスはフォーカスが外れないとchangeイベントが検知できないので
「即時」反映を実現しようと思ったらkeyupやkeydownイベントを組み合わせて、
もうちょっと複雑な実装をしなければいけません。
参考:jQueryでテキストボックスの変更を監視/検知する
これをAngularJSを使うと以下のようになります。
<script type="text/javascript" src="/js/angular.js"></script> <div ng-app> <input type="text" ng-model="hoge" /> <div ng-bind="hoge"></div> </div>
1行目はjQueryなどと同様にまずAngularJS本体を読み込みます。
その下のHTMLタグ内で登場する「ng-app」「ng-model」「ng-bind」といった「ng-」で始まる見慣れないHTMLプロパティがAngularJS独自の「ディレクティブ」というものです。
3行目の「ng-app」はAngularJSを使用するための下準備のようなもので、このディレクティブを付与した要素内のDOMにAngularJSが適用されます。
特に制限なくページ全体でAngularJSを使用したい場合には<html>タグに付与してしまえばOKです。
4行目の「ng-model」はその名の通りモデル(データ)を管理します。ここではテキストボックスに入力されたデータを「hoge」という名前で保持します。
5行目の「ng-bind」はモデルをビューにデータバインディングします。この<div>タグ内に「hoge」という名前で保持したモデルを反映します。
ちなみに「ng-bind」を使用している5行目は「{{}}」の記号を使って以下のように書き換えることが可能です。
<div>{{hoge}}</div>
一般的にはこの省略形が使用されることが多いですが、AngularJSを読み込むまでの時間に、ページ上に{{hoge}}と表示させたくない場合は「ng-bind」で書くと回避できます。
ひとつ目に記載したjQueryのサンプルコードでは、テキストボックスからフォーカスが外れた時にchangeイベントを取って値が反映されていましたが、
AngularJSではデータバインディングされているので入力している最中にリアルタイムで即時反映が可能となっています。
このように、AngularJSでは独自のディレクティブを付与することで、HTMLドキュメントをそのままテンプレートとして使用して、データバインディングでダイナミックにビューを変化させることが可能です。
この程度の実装なら自分でJavaScriptのコードを書く必要すらないんですね!
繰り返し処理
さて、上記で使用したAngularJSの特徴であるディレクティブですが、自分でオリジナルのディレクティブを自作することも可能ですし、もちろんさまざまな機能をもったものが予めビルトインで用意してあります。
一例として、簡単な繰り返し処理を見てみましょう。
<script type="text/javascript" src="/js/angular.js"></script> <div ng-app> <ul ng-init="fruits=['apple','grape','orange']"> <li ng-repeat="fruit in fruits">{{fruit}}</li> </ul> </div>
4行目の「ng-init」でモデルの初期化をしています。ここでは複数のフルーツが入ったfruitsという配列を定義しています。
5行目の「ng-repeat」で要素の繰り返しをします。繰り返し条件「fruit in fruits」でfruits配列内の値をfruitとしてひとつずつ取り出しています。
いかがでしょうか?簡単な繰り返し処理を非常にスッキリ記述することが可能となっています。
MVC
さて、基本的な使い方を見てきましたが、実際にwebアプリを作成する際にMVCフレームワーク的に使う場合のやり方を少し見てみましょう。
ビュー(HTMLテンプレート)としてindex.htmlを用意し、コントローラとしてmyController.js、モデルとしてmyModel.jsを別ファイルで以下のように作成してみます。
やや難易度が上がるのでパッと見では何をやっているかわからない部分が多いかとは思いますが、
AngularJSで書くとこんな感じになるんだなぁという雰囲気だけでも掴んでいただけると幸いです。
index.html
<!doctype html> <html lang="ja" ng-app='app'> <head> <meta charset="utf-8"> <script type="text/javascript" src="/js/angular.js"></script> <script type="text/javascript" src="/js/myModel.js"></script> <script type="text/javascript" src="/js/myController.js"></script> </head> <body ng-controller="MyController"> <h1>Food List</h1> <ul> <li ng-repeat="food in foods">{{food.name}} ({{food.category}})</li> </ul> <h1>Fruits List</h1> <ul> <li ng-repeat="fruit in fruits">{{fruit}}</li> </ul> </body> </html>
myController.js
angular.module('app', ['MyModel']) .controller('MyController', ['$scope', 'Model', function($scope, Model) { $scope.foods = Model.foods; $scope.fruits = Model.getFruits(); }]);
myModel.js
angular.module('MyModel', []) .factory('Model', function() { var Model = {}; Model.foods = [ {'category':'fruits', 'name':'apple'}, {'category':'vegetables', 'name':'cabage'}, {'category':'vegetables', 'name':'tomato'}, {'category':'fruits', 'name':'orange'} ]; Model.getFruits = function () { var fruits = []; for(i=0; i<Model.foods.length; i++){ if(Model.foods[i].category == 'fruits'){ fruits.push(Model.foods[i].name); } } return fruits; }; return Model; });
まず、テンプレートであるindex.htmlでは、
2行目でAngularJSを使用するために「ng-app」ディレクティブを、自作のモジュール名「app」を指定して<html>要素に付与しています。
これで自作のモジュール「app」を使用することが出来ます。
6,7行目で各jsファイルを読み込んでいます。
9行目に「ng-controller=”MyController”」というのがあります。
ここで別途定義した自作のコントローラー「MyController」を指定しています。
myController.jsでは、1行目でAngularJSのモジュールとして「app」を定義しています。
第2引数の[‘MyModel’]というのは、別途定義した「MyModel」というモジュールに依存していることを表しています。(依存性注入)
そのモジュールに2行目「.controller()」メソッドでコントローラーとしての機能を付加しています。
第1引数にはコントローラー名「’MyController’」を指定しています。
第2引数では依存するサービスを注入しています。今回は「$scope」サービスと自作の「Model」サービスを注入しています。
「$scope」というのは、index.htmlの9行目で「ng-controller=”MyController”」ディレクティブが付与されていますのでこのDOMがスコープされてデータバインディングされます。
第2引数の配列の一番最後にコントローラーのコンストラクター関数を渡しています。
ここら辺は最初非常にとっつきにくい部分となるかと思います。
私自身もとても100%理解するには至っておりませんが、
まずはそんな決まりなんだと思ってたくさんコードを書いて慣れていくしかないのかなと思っております。
myModel.jsでも同様に、1行目で「MyModel」というモジュールを作成し、
2行目の「.factory()」メソッドでfactoryサービスとしての機能を付加しています。
(モデルはこの「factory」サービスや「service」サービスなどを使って作成することになるかと思います。)
このfactoryサービスに第1引数の「Model」という名前を付け、第2引数の関数内でさまざまなデータ処理を記述するかたちになります。
ここでは、さまざまな食べ物の情報を返す配列foodsと、その配列からフルーツだけ抜き出して名前だけの配列を返すメソッドgetFruits()を定義してみました。
このModelから返したfoodsとgetFruits()をmyController.jsの3,4行目でコントローラーのスコープ内の各変数にセットしています。
このコードを実行すると以下のような表示になります。
使ってみた感想
やはり、フレームワークというだけあって、
ライブラリとして読み込んですぐに便利な機能がサクッと使える「jQuery」などとは根本的に考え方は異なって、設計の段階から十分に検討の上でAngularJSをベースにwebアプリを作成していく、
といったイメージになるかと思いました。
ディレクティブなどの独自の機能がベースになるので学習コストもなかなかかかってしまいます。
実際に案件で使用する際には、設計段階で本当に使用した方がよいケースなのか十分に検討した上で使用するのがいいかと思いました。
いかがでしたでしょうか?
今回は「入門編」としてAngularJSの基本的な使い方をざっくりご紹介しました。
また機会があったらより深い部分もご紹介できたらと思います。
AngularJSって最近よく聞くけど、ちょっと試してみようかな?という人の一助になれば幸いです。
スパイスワークスでは、今後も新しい技術を積極的に取り入れ、
さまざまなニーズに対応できるように精進していきたいと思います!