AngularJSとBootstrapを組み合わせてUIコンポーネントを作ってみよう
AngularJSで初めるJavaScriptフレームワーク開発スタイル 第12回
入力コンポーネントを作ってみる(2)
ngModelと連携した実装
続いて、ngModelと連動するようそれぞれの中身を実装していきます。buttonGroupディレクティブで使用されるButtonGroupControllerの中身はリスト7のようになります。
function ButtonGroupController($scope){
var items = [];
//(1)選択(クリック)されたボタンのスタイルを変更する
function select(value){
for(var i = 0; i < items.length; i++){
var $_scope = items[i];
if($_scope.value == value){
$_scope.active = true;
}
else{
$_scope.active = false;
}
}
}
//(2)buttonItemの$scopeを追加するメソッド
this.addItem = function($_scope){
items.push($_scope);
};
//(3)外部からの変更を受け付けるメソッド
this.setValue = function(val){
select(val);
};
//(4)コンポーネント内での変更を受け付けるメソッド
this.select = function($_scope){
select($_scope.value);
//(5)変更時にはイベントでディレクティブへ値を通知する
$scope.$emit('change',$_scope.value);
}
}
(1)ではボタンがクリックされた時にアクティブな要素の指定を行う共通関数を定義しています。また、(2)では子のbuttonItemディレクティブ(スコープ)を把握できるようにメソッドを作成します。このメソッドは、buttonItemディレクティブでのlinkメソッドから利用します。
続いて(3)ではコンポーネント外で値が変わったときに、その値を反映させるためのメソッドです。そして、最後にコンポーネントでの値の変更、つまり、ボタンをクリックしたときに実行されるメソッドが(4)のようになります。
(3)と同様にボタンをアクティブな値の設定を行いつつ、(5)のように変更のタイミングでイベントは発火するようにしています。これは、スコープを共有するbuttonGroupに変更を通知するためです。
続いて、buttonItemのlinkメソッドはリスト8のように実装します。
//(1)buttonGroupControllerの利用
var link = function($scope,$element,$attrs,buttonGroupController){
//(2)buttonGroupControllerへ追加
buttonGroupController.addItem($scope);
//(3)要素を選択した時の処理
$element.click(function(){
buttonGroupController.select($scope);
});
};
(1)ではlinkメソッドの第4引数でbuttonGroupControllerのインスタンスを取得しています。そして、(2)では先ほど作成したaddItemメソッドで要素オブジェクトの$elementを登録することと、その要素がクリックされた時に(3)のようにselectメソッドを呼びます。
ここまでできれば、見た目の部分の作成は完成したといえます。
続いて、ngModelとの連携をするために、buttonGroupディレクティブのlinkメソッドをリスト9のように実装します。
var link = function($scope,$element,$attrs,controllers){
//(1)requireで指定した順番でcontrollerが配列で取得可能
var buttonGroupController = controllers[0];
var ngModelController = controllers[1];
//(2)ngModelの値が外部より変更されたときによばれるメソッドの定義
ngModelController.$render = function(){
buttonGroupController.setValue(ngModelController.$viewValue);
};
//(3)値が変わったときにngModelで双方向バインディングされている変数への値の設定
$scope.$on('change',function(evt,val){
ngModelController.$setViewValue(val);
});
};
buttonGroupディレクティブのrequire属性では、配列を用いて依存を指定したため、linkメソッドの第4引数のコントローラも配列でわたってきます。従って、(1)のようにコントローラを取得する際には順番に気をつけて取得する必要があります。
(2)では、外部から値を変更されたときの処理で、NgModelControllerでは値の変更時には$renderメソッドが呼ばれますのでその処理を定義します。また、コンポーネントから値が変更されたときは(3)のように$setViewValueメソッドで値を変更します。その他、ここで使っている関数や変数の意味を知るにはNgModelControllerのリファレンスを参照して下さい。
もっと便利なコンポーネントにするために
ngModelを使えばformディレクティブと連携して機能することができます。ただし、これまでの実装だけではformディレクティブを使う際に有効なバリデーションが機能していません。
サンプルコードでは実際にformディレクティブとバリデーション部分で連携するように追加のコードがあります。
これらのサンプルコードを参考に、より便利なコンポーネントに自分好みのカスタマイズをしていただければと思います。
最後に
実はBootstrapとAngularJSを連携したライブラリはUI Bootstrapというものが既に存在します。従って、早急にBootstrapを組み込みたいならこのライブラリを使えばよいのですが、汎用的に作られているので指定できるオプションも非常に多岐にわたり、Bootstrapを知らないと使いにくいところがあります。実際のプロジェクトなどでは用途も定まっているために、もっと簡略化するためや、ng-includeなどの代わりにカスタムディレクティブを使えば、さらに効率のよい開発ができるのではないかと思います。
参考資料
この記事は参考になりましたか?
既に会員の方はを行ってください。
- AngularJSではじめるJavaScriptフレームワーク開発スタイル連載記事一覧
-
- AngularJSと組み合わせて便利なライブラリ、RequireJSを使ってコード管理を簡...
- AngularJSのngRouteを使ってシングルページアプリケーション(SPA)を作って...
- AngularJSとBootstrapを組み合わせてUIコンポーネントを作ってみよう
- この記事の著者
-
山田 祥寛(ヤマダ ヨシヒロ)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)
< WINGSプロジェクト について> 有限会社 WINGSプロジェクト が運営する、テクニカル執筆コミュニティ(代表 ...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
