指定期間でDOMを出し分けてくれるangular-periodを公開しました
angular-periodとは
AngularJS のDirectiveで、期間を指定するとその 期間前、期間中、期間後でDOMの表示を切り替えてるようにするものです。
例えば、なんかの応募とかで、以下の様なHTMLをテンプレートエンジンやJavaScriptなどを使って出し分けることがある時に便利です。
angularJSを使った一番お手軽なケースとしてはこんなかんじでしょうか。
angular.module("campaign", []) .controller('CampaignCtrl", function () { this.now = new Date().getTime(); this.start = new Date('2015-08-01T00:00:00').getTime(); this.end = new Date('2015-08-31T23:59:59').getTime(); });
<div class="campaign" ng-controller="Campaign as campaign"> <!-- 期間前の表示 --> <div class="form is-previous" ng-if="campaign.now < campaign.start"> <p>○月☓日から応募できます</p> <!-- 期間中の表示 --> <form class="form" ng-if="start <= campaign.now && campaign.now <= campaign.end"> <button type="submit">応募する!</button> </form> <!-- 期間後の表示 --> <div class="form is-after" ng-if"campaign.end < campaign.now"> <p>応募は締め切りました</p> </div> </div>
angular-periodを使えば、以下のように書けます。
angular.module('campaign', ['angularPeriod']);
<div class="campaign" ng-period ng-period-start="'2015-08-01T00:00:00'" ng-period-end ="'2015-08-31T23:59:59'"> <!-- 期間前の表示 --> <div class="form is-previous" ng-period-when="previous"> <p>○月☓日から応募できます</p> <!-- 期間中の表示 --> <form class="form" ng-period-when="during> <button type="submit">応募する!</button> </form> <!-- 期間後の表示 --> <div class="form is-after" ng-period-when="after"> <p>応募は締め切りました</p> </div> </div>
開始と終了を渡すと、その期間の前、中、後のHTMLを選択してDOM Treeに組み込みます。 最も単純なケースではコントローラーすら不要なので、ロジックやテストを大幅に削減できます。
また、angular-periodはリアルタイムな反映及び、setTimeoutの上限値である32bit intを超える値もサポートできるようにしているので、長期にわたる期間であってもある程度は許容されます。
インストール
npm, bowerともに公開しているので必要な方を利用してください。
npm install angular-period
bower install angular-period
日付の指定とパースについて
利用可能な値
上記には文字フォーマットを用いた例を記載しました。 ただ、実際にプログラムする上で文字列だけでは様々な不便なことがあるでしょう。
ngPeriodは Date
オブジェクトに変換可能な値をサポートしています。
具体的には、
- Date
のパース可能な文字列
- Date
オブジェクト
- momentjsなどのDateオブジェクトに渡せるオブジェクト
先ほどの例で、例えばmomentjsを使う場合は以下の様に書けます。
angular.module('campaign', ['angularPeriod']) .controller('CampaignCtrl", function () { this.start = moment('2015-08-01 00:00:00'); this.end = moment('2015-08-31 23:59:59'); });
<body ng-controller="Campaign as campaign"> <div class="campaign" ng-period ng-period-start="campaign.start'" ng-period-end ="campaign.end"> <!-- 期間前の表示 --> <div class="form is-previous" ng-period-when="previous"> <p>○月☓日から応募できます</p> <!-- 期間中の表示 --> <form class="form" ng-period-when="during> <button type="submit">応募する!</button> </form> <!-- 期間後の表示 --> <div class="form is-after" ng-period-when="after"> <p>応募は締め切りました</p> </div> </div> </body>
至ってシンプル。
パースできない値
Dateオブジェクトでパース可能な値はブラウザによって異なります。
パースできない値を渡すと、Dateは Invalid Date
というオブジェクトを返すので、
それをそのままDateとして扱おうとすると、Nanだったり不適切な値になりえます。
困るケースでは、ChromeとSafariで利用可能なDateのフォーマットが異なるという点です。
Chromeは YYYY-MM-DD HH:mm:ss
という値をサポートしていますが、SafariではInvalid Date
が返ってきます。
これは失念すると非常に気づきにくくリスキーで、常にChromeとSafariでの動作確認を要求されるため大変不便です。
angular-periodでは、Invalid Date
になるような値を渡された場合その時点でErrorオブジェクトをthrowするようにはしています。
JavaScriptのDateオブジェクトは非常に複雑かつブラウザ間で挙動が違うので、それを吸収するよりは、すでに実装され安定的に運用されている他のモジュール(momentjsのような)を利用することを推奨します。
まとめ
というわけで結構便利なモジュールを書いたつもりで居るのでどうぞお試しあれ。