AngularJS で共通変数的なアレを定義する
先日(7/3)開催した ng-mtg#3 AngularJS 勉強会 1周年記念! の @agektmr さんのセッションで紹介された、AngularJS のベストプラクティスです。
デモで使われたコードはこちらです。
AngularJS を使ってみると、個々に controller や directive をあれこれするのはさほど難しくないのですが、例えば、controller A で使う変数と directive B で使う変数を共通で使いたい場合に、これを知らないと悩むんじゃないかな〜と思います。
angular.module() の .value() というメソッドを使います。
( 厳密には $provide.value() ですけど気にしない! )
1.定義する
まずはモジュール( myModule とします )を作ります。
その後に .value() として、引数に key - value 形式で共通変数にしたいデータを定義します。
こうすることで myModule 内で共通的に使えるオブジェクトが定義できます。
angular.module('myModule', ).value(
'keyName', {
'value1': 'can',
'value2': ['i', 'do', 'web'],
'value3': 12345
}
);
2.つかいかた
上のコードにさらにコードを追記して、.value() で定義したデータを使ってみます。
angular.module('myModule', ).value( 'keyName', { 'value1': 'can', 'value2': ['i', 'do', 'web'], 'value3': 12345 } ) .controller('myController', function($scope, keyName){ $scope.someModel = keyName.value1; }) .directive('myDirective', function(keyName){ return { // 省略 } });
追記したコードは controller と directive を作っただけのものになりますが、 それぞれの function の記述の引数に 1.で定義した keyName というオブジェクトを渡しています。
こうすることで、controller でも directive でも共通的な変数を扱うことができます。
ちょー簡単&便利!
controller の方を見ると、$scope.someModel というモデルに値をバインディングして使ったりもできます。
これは絶対覚えておくべきですよー!!
AngularJS のマウスイベント
AngularJS でのマウスイベントをとってみました。
今回は実験的にですが jsdo.it にデモをアップしてみました。
自前のサイトにアップするより、コードをちょこっと試すのには良いですね〜。
ただし、挙動がちょっと怪しいのはご容赦を(笑)
なんか特定のイベント処理が捌けないときがあります(これはボクのコードのせいかもしれないですが・・・)
イベントの登録・取得
今回は以下のイベントを捕捉してみました。
右側の ng-xxx が AngularJS での記述方法になります。
- click:ng-click
- double click:ng-dblclick
- mouse down:ng-mousedown
- mouse move:ng-mousemove
- mouse up:ng-mouseup
- mouse enter:ng-mouseenter
- mouse over:ng-mouseover
- mouser leave:ng-mouseleave
使い方はデモと合わせて見ていただきたいですが、
<div ng-click="click()"><div>
と記述します。
いわゆる onclick="click()" を AngularJS 流に書くとこうなります。
今回は1つのdivに先ほどのイベントを全部登録して、発生したイベントをただリスト表示しているだけですので、処理の内容については特に触れません。
イベントのリスト表示( ng-repeat )
<div id="eventLog"> <p ng-repeat="event in events"> {{event.type}} ...(省略) </p> </div>
events から中身を1つずつ取り出して、そこからtypeを取得・表示しています。
jQuery でいうところの $.each() と同じような感じになります。
※events の中身はハッシュオブジェクトの配列
{ 'type': 'click', 'count': 1 }, { 'type': 'mouse move', 'count': 10 }, ... { 'type': 'mouse leave', 'count': 1 }
Facebook のいいねのとこのアレ( ng-pluralize )
いいねのところって、1人の時と複数人の時とかで表記が違っていますよね。
- ○○さんがいいねといっています。
- ○○さんと○○さんと他○○名がいいねといっています。
AngularJS では、この振り分けするための機能も用意されています。
<span ng-pluralize count="event.count " when="{ 'one': '', 'other': ' * {{event.count}}' }"></span>
ng-pluralize の記述と count="対象" when="{ 設定 }" で指定します。
今回のデモでは、同じイベントが続けて実行された場合、実行回数をまとめて表示するようにしていて、実行回数が1回の時は何も表示しない、それ以外(2回以上)は実行回数を表示します。
うまく説明できてないですが、コードを少しに触ってみて頂けるとわかるかな〜と思います。本家サイトのAPIの方がわかりやすいかも。。。
気軽にコードを試してもらえるように、今回から jsdo.it にアップをしています。
よろしかったら遊んでみてください。
ということで、今回はこの辺で。
AngularJS 地味だけど知っておきたい filter 機能
前回から間があいてしまいましたが。。。
今回はAngularJS が提供している filter についてまとめてみました。
まとめたものがコチラ
デフォルトで用意されているのは以下です。
- lowercase
- uppercase
- json
- currency
- date
- limit
- number
- orderBy
これら以外にも自分で実装することもできますが、今回は説明しません。
徐々に紹介していけたらと思っています。
主観ですが、date, limit, orderBy が非常に優秀だと感じました。
lowercase / uppercase
{{ plainText | lowercase }} {{ plainText | uppercase }}
これ日本語という観点で考えると使い道が。。。使う頻度は少ないと思います。
json
{{ jsonFilter | json }} // ※jsonFilter はハッシュオブジェクト
これは、ハッシュオブジェクトを json オブジェクトに変換するのに役立ちます。
ただし、ハッシュオブジェクト内に json 形式でないオブジェクト(functionなど)があると、json オブジェクトには変換されません。
多くのアプリやサービスでは、データのやり取りの多くが json オブジェクトだったりしますので、利用する機会はあるかと思います。
currency
default($) : {{amount | currency }} custom (¥) : {{amount | currency:"¥" }}
通貨単位(デフォルトは「$」)をくっつけてくれたり、$1,000 のように3桁ごとに「,」区切りにしてくれたりします。もちろん「¥」に変更することもできます。
ただ、¥1,000.00 となってしまって、最後の .00 要らない・・・となってしまい、スマートに取り除く方法がわかりませんでした。(誰かこっそり教えてください)
date
{{ dateFilter | date:'medium' }} {{ dateFilter | date:'yyyy-MM-dd HH:mm:ss Z' }} {{ dateFilter | date:'yyyy年MM月dd日' }}
これはそのままでも使えるのですが、localization することで非常に使い勝手がよくなります。年月日を表示したいだけに使うならこのままでも問題ありません。曜日を表示したい場合は、やはり localization する必要があります。
localization の方法については次回に紹介しようと思ってます。
limit
{{ arrays | limitTo:limit }}
指定した数値で配列の表示件数を制限してくれます。
number
{{val | number}} {{val | number:0}} {{-val | number:4}}
小数点以下の表示桁数の制御等を指定できます。
計算結果を表示する際にこの filter を通しておけば、33.333... のようなレイアウト崩れを防げたりできるのではないでしょうか。
orderBy
<p><button ng-click="order='name'">order by name</button><button ng-click="order='id'">order by id</button></p> <ul ng-repeat="data in sampleData | orderBy: order"> <li>name : {{data.name}}, id: {{data.id}}</li> </ul>
ng-click を利用してソート対象を切り替えていてるのですが、実際にソートする箇所は ng-repeat と組み合わせて利用します。これがホントに優秀で、配列になっているハッシュオブジェクトであれば、keyを指定すればソートしてくれます。引数に「reverse」とすることで逆順にソートもできてしまいます。
リストの絞り込み
<ul ng-repeat="data in sampleData2 | filter:search"> <li>{{data.name}} </ul>
サンプルの最後に、表示されているリストを絞り込むサンプルを作ってみました。
入力値でフィルタリングされるので、絞り込みのUIを実現できます。
filter まとめ
まー、地味です。とはいえ、知らないで同じような機能を自身で実装してしまったら最悪です。「ちょっと書いたらできたし・・・」的な後悔とヘコみっぷりが半端ないです。
データをちょっと加工したい、そう思ったらこの filter を1度チェックしてみるとよいかもしれません。
AngularJS 使って手軽でリッチな入力フォームを作ってみた
意外とAngularJSを使った入力フォームのサンプルが無かったので作ってみました。
まず作ったものがコチラ
AngularJSを使えば手軽にシンプルかつリッチな入力フォームを作ることができます。自前のJavaScriptを用意すればさらに凝ったものも作ることができますが、今回は自前のJavaScriptを使わないでもこれだけできます!というサンプルです。
個別のバリデーションチェック
サンプルで行われているバリデーションは、全てAngularJSによるもので、JavaScriptによるコードの記述は一切書いていません。その代わりに、以下のような記述でチェックする内容を指定しています。
<form method="post" name="userInfo"> ... <input type="text" name="userName" ng-model="userName" ng-minlength="6" ng-maxlength="12" required> <span class="error" ng-show="userInfo.userName.$error.required">必須</span> <span class="error" ng-show="userInfo.userName.$error.minlength">6文字以上です</span> <span class="error" ng-show="userInfo.userName.$error.maxlength">12文字までです</span> <span class="valid" ng-show="userInfo.userName.$valid">OK</span> ... </form>
input要素にあるng-minlength、ng-maxlength、required 属性がチェック内容を指定する記述です。チェック内容は見たままですのでわかりやすいと思います。
これを記述するだけで、それぞれのチェックをしてくれます。
それぞれのチェック結果は、userInfo.userName.$error.required、userInfo.userName.$error.minlength、userInfo.userName.$error.maxlength に保持されます。
これをinput属性以降のspanタグにある ng-show="xxxx" と組み合わせることで、それぞれのエラーに対応するエラーメッセージを表示させています。
1つ注意すべきはエラーの場合 true、チェックOKの場合は falseが格納されますのでご注意を。
また、userInfo.userName.$valid とありますが、これはエラーではなく、チェックOKの場合に true が格納されます。こちらについては、後で説明します。
AngularJS の双方向バインディング
<form method="post" name="userInfo"> ... <input type="password" name="password" ng-show="!showPassword" ng-model="password" required> <input type="text" name="plainPassword" ng-show="showPassword" ng-model="password" required> <span class="error" ng-show="userInfo.password.$error.required">必須</span> <span class="valid" ng-show="userInfo.password.$valid">OK</span> <div><input type="checkbox" id="showPassword" ng-model="showPassword"><label class="comment" for="showPassword">パスワードを表示する</label></div> ... </form>
これだけできます。
ただし、required 以外のバリデーションチェックを定義すると、チェックエラーの際にng-modelの値が undefined になるため、同名で定義されたもう一方の値を更新してしまっているようで、結果おかしな動きになってしまいました。。。この場合は、JavaScriptを自前で用意して定義する必要がありそうです。ng-change 属性を定義すれば、自前で実装したJavaScript内でイベントをフックできます。
正規表現よるバリデーションチェック
正規表現を用いたバリデーションチェックも定義することができます。メールアドレスに対しては、今回は手抜きで gmail であるかどうかをチェックしています。
<form method="post" name="userInfo"> ... <input type="mail" name="mail" ng-model="mail" ng-pattern="/^.+@gmail\.com$/"> <span class="comment">任意</span> <span class="error" ng-show="userInfo.mail.$error.pattern">gmailのみですー</span> <span class="valid" ng-show="userInfo.mail.$valid">OK</span> ... </form>
エラーハンドリングについては、前述した通りです。
入力文字数を扱う
わかりやすく、twitterの残り入力文字数としてみました。
<form method="post" name="userInfo"> ... <span ng-show="userInfo.twitter.$error.maxlength"><ng-show="userInfo.twitter.$error.maxlength" class="error">140文字こえてますよー</span> <span ng-hide="userInfo.twitter.$error.maxlength">{{140 - twitter.length}}</span> <textarea name="twitter" rows="10" ng-model="twitter" ng-maxlength="140"></textarea> <span class="comment">任意</span> <span class="valid" ng-show="userInfo.twitter.$valid">OK</span> ... </form>
{{140 - twitter.length}}とすることで、残りの入力文字数を変更させています。
140文字を超えた場合は、エラーメッセージが表示されます。
formのsubmitボタンの状態変更
<form method="post" name="userInfo"> ... <input type="submit" value="登録" ng-disabled="userInfo.$invalid"> <span ng-show="userInfo.$invalid" class="comment">未入力の項目や正しく入力できていない項目があります</span> <span ng-show="userInfo.$valid" class="comment">入力チェックOK!</span> ... </form>
このsubmitボタンは、デフォルトではdisableとなっていてクリックすることができません。form内の項目全てのバリデーションチェックがOKになったときのみクリックできるようになります。こういったよくある仕組みも、自前で実装するのは結構手間だったりします。
AngularJS では、form内の要素すべてがvalidかinvalidか、さらに個々の要素に対してもvalidかinvalidの可否を取得することができます。先述した userInfo.userName.$valid であったり、この form 自体の userInfo.$valid がそれにあたります。
userInfo.userName.$valid であれば、 ng-minlength、ng-maxlength、required の全てがチェックOKであれば true になります。どれか1つでもエラーなら false になります。同様に userInfo.$valid とすれば、全入力項目でのチェックがOKであれば true となります。
とにかく簡単でした
コードを見ていただければわかると思いますが、JavaScript を自前で用意しなくてもこれだけのことができてしまいます。モックの作成でも利用できますし、WEBサイトのいわゆるマイページのようなSSL配下のページ群もWEBアプリケーション化することを目的として利用することもできるのではないかなーと思いました。
AngularJS 中心のブログはじめてみる
AngularJS を日本でも盛り上げるべく不定期ながらも書いていこうと思います。
まだまだ日本語でのブログやサンプル少ないですよね。
なので少しでも取っ掛かりになるようなサンプルやデモを作って紹介できたらなー、と思ってます。
関係ないのも書くかもしれませんが。。。
また、日本語で議論や質問ができるように AngularJS Japan User Group というグループがあります。ここで管理人をやらせて頂いています。ご興味ある方は、ウォッチしてみてください。
ではでは。