今回は Aurelia で Date Range Picker を使う方法について書いていきます。
最終的に、下図の「Expiry Period」のようになります。
日付を範囲選択したい場合に便利ですので、宜しければご覧ください。
また、解説不要な人のために GitHub リポジトリの URL を載せておきますね。
https://github.com/phayacell/aurelia-daterangepicker
該当のコミットはこちら。
https://github.com/phayacell/aurelia-daterangepicker/commit/23643928914ce9e98958e04f5ec20c5907092b74
Date Range Picker とは
A JavaScript component for choosing date ranges, dates and times.
jQuery と Moment.js に依存する日付範囲選択のためのツールですね。時刻も含めて選べます。
動くサンプルは Examples に載っているので、イメージを掴みやすいです。
TL;DR
- 日付の範囲選択を Datepicker でゴニョゴニョするのが疲れた人は Date Range Picker がオススメだよ
- Aurelia でどう使うのか、導入する手順を書いたよ
対象読者
Aurelia で Date Range Picker を使おうと考えている人。
前提環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.11.6
BuildVersion: 15G22010
$ yarn -v
1.7.0
導入するもの
事前準備
Aurelia - Contact Manager Tutorial を済ませておいてください。1
今回はそちらに「有効期限」を追加する形で実装していきます。
Tutorial をやるのが面倒な人は、以下で引っ張ってきても良いです。
Date Range Picker を導入する直前の状況を再現できます。
$ git clone git@github.com:phayacell/aurelia-daterangepicker.git
$ cd aurelia-daterangepicker
$ git checkout 47e25155d22943a373266bd9ce79b021a1c8eae4
導入手順
1. Date Range Picker をインストール
npm で管理されているので、インストールは楽ちんです。
私は yarn を使っているので以下のコマンドです。npm の人は適宜読み替えてください。
$ yarn add daterangepicker
2. Date Range Picker を扱う Custom Element を作成
src
配下に、以下の3ファイルを作成してください。
date-range-picker.html
date-range-picker.js
date-range-picker.css
以降、それぞれに記載する内容と解説を書いていきます。
src/date-range-picker.html
必要な css を読み込んで、側を作るだけなので、そこまで難しくないです。
.form-control
クラスを設定しているので Bootstrap の Form controls に則ることができるようにしてあります。
.input-group
クラスなども適用できるってことですね。
<template class="form-control">
<require from='daterangepicker/daterangepicker.css'></require>
<require from='./date-range-picker.css'></require>
<div class="date-range-picker">
<span class="date-range">
<time datetime="${startDate}">${startDate}</time>
<span>-</span>
<time datetime="${endDate}">${endDate}</time>
</span>
</div>
</template>
src/date-range-picker.js
いくつかのブロックに分けて解説するので、先に完成形を書いておきます。
import { inject, bindable, bindingMode } from 'aurelia-framework';
import $ from 'jquery';
import moment from 'moment';
import 'daterangepicker';
@inject(Element)
export class DateRangePicker {
@bindable({defaultBindingMode: bindingMode.twoWay}) startDate;
@bindable({defaultBindingMode: bindingMode.twoWay}) endDate;
@bindable({defaultBindingMode: bindingMode.oneTime}) options;
constructor(element) {
this.element = element;
}
created(owningView) {
this.owningView = owningView;
}
attached() {
this.options = $.extend(true, {
locale: {
format: moment.HTML5_FMT.DATE
}
}, this.options);
this.options = $.extend(this.options, {
startDate: moment(this.startDate, this.options.locale.format),
endDate: moment(this.endDate, this.options.locale.format)
});
$(this.element).daterangepicker(this.options, (start, end) => this.apply(start, end));
}
apply(startDate, endDate) {
this.startDate = startDate.format(this.options.locale.format);
this.endDate = endDate.format(this.options.locale.format);
}
startDateChanged(newValue) {
if (this.owningView.isAttached) {
$(this.element).data('daterangepicker').setStartDate(newValue);
}
}
endDateChanged(newValue) {
if (this.owningView.isAttached) {
$(this.element).data('daterangepicker').setEndDate(newValue);
}
}
}
まずは import 部分。
使用する jQuery, Moment.js を読み込み、Date Range Picker を読み込ませて jQuery に Mixin しています。
import { inject, bindable, bindingMode } from 'aurelia-framework';
import $ from 'jquery';
import moment from 'moment';
import 'daterangepicker';
次に宣言。
startDate
と endDate
は双方向バインドする必要があるので bindingMode.twoWay
を指定。
options
は Date Range Picker のオプションを利用側から扱えるようにしています。オプションの詳細は Options で。
@inject(Element)
export class DateRangePicker {
@bindable({defaultBindingMode: bindingMode.twoWay}) startDate;
@bindable({defaultBindingMode: bindingMode.twoWay}) endDate;
@bindable({defaultBindingMode: bindingMode.oneTime}) options;
次にコンストラクタとか。
element
は Date Range Picker を使うために必要です。jQuery Plugin を使う場合によく見ますね。
owningView
は startDate
と endDate
の変更監視メソッド内で attached 後かどうかを判定するために使います。
constructor(element) {
this.element = element;
}
created(owningView) {
this.owningView = owningView;
}
次に attached
です。
$.extend(true, {/* default */}, {/* override */})
の形で書いていますので、bind された options の値を優先させます。
また、startDate
と endDate
は twoWay bind で渡された値を優先させています。
options の設定が終わったら、Date Range Picker の初期化。
値が反映された時のメソッドは apply(start, end)
で定義してあります。
また、moment.HTML5_FMT.DATE
は Special Formats を参考にしています。
attached() {
this.options = $.extend(true, {
locale: {
format: moment.HTML5_FMT.DATE
}
}, this.options);
this.options = $.extend(this.options, {
startDate: moment(this.startDate, this.options.locale.format),
endDate: moment(this.endDate, this.options.locale.format)
});
$(this.element).daterangepicker(this.options, (start, end) => this.apply(start, end));
}
次に Date Range Picker の反映処理。
引数で渡ってくる値は Moment.js のインスタンスになっていますので、これを文字列に変換しています。
twoWay bind している startDate
と endDate
に設定しているので、この Custom Element の利用側の変数にも反映されます。
apply(startDate, endDate) {
this.startDate = startDate.format(this.options.locale.format);
this.endDate = endDate.format(this.options.locale.format);
}
最後に startDate
と endDate
の変更検知メソッド。
Aurelia では Observable Properties を使って変数の変更検知を行うことができますが、bind される変数も使えます。
ここでは、この Custom Element 外から値を変更された場合に Date Range Picker の選択範囲に反映されるようにしています。
ちょっと特殊なのは if (this.owningView.isAttached)
ですね。
$(this.element).data('daterangepicker')
は attached されていないと存在しないため、この判定を行っています。
startDateChanged(newValue) {
if (this.owningView.isAttached) {
$(this.element).data('daterangepicker').setStartDate(newValue);
}
}
endDateChanged(newValue) {
if (this.owningView.isAttached) {
$(this.element).data('daterangepicker').setEndDate(newValue);
}
}
src/date-range-picker.css
最後にスタイルの設定です。
flexbox を使ったり、擬似クラスの before/after を使ったりしています。
あと、チュートリアルで組み込まれていた Font Awesome も使っています。
.date-range-picker {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.date-range-picker::before {
font-family: FontAwesome;
content: '\f073';
padding-right: .5rem;
flex: 0 0 auto;
}
.date-range-picker::after {
font-family: FontAwesome;
content: '\f0d7';
padding-left: .5rem;
flex: 0 0 auto;
}
.date-range-picker .date-range {
flex: 1 1 auto;
display: flex;
justify-content: space-around;
align-items: center;
}
3. 作成した Custom Element を使う
いよいよ Contact で「有効期限」を扱える手順です。
Contact Manager では WebApi に初期データが作られているので、これに有効期限の from と to を追加します。
let contacts = [
{
id: getId(),
firstName: 'John',
lastName: 'Tolkien',
email: 'tolkien@inklings.com',
phoneNumber: '867-5309',
expiryFrom: '2017-01-01',
expiryTo: '2019-01-01'
},
{
id: getId(),
firstName: 'Clive',
lastName: 'Lewis',
email: 'lewis@inklings.com',
phoneNumber: '867-5309',
expiryFrom: '2017-01-01',
expiryTo: '2019-01-01'
},
{
id: getId(),
firstName: 'Owen',
lastName: 'Barfield',
email: 'barfield@inklings.com',
phoneNumber: '867-5309',
expiryFrom: '2017-01-01',
expiryTo: '2019-01-01'
},
{
id: getId(),
firstName: 'Charles',
lastName: 'Williams',
email: 'williams@inklings.com',
phoneNumber: '867-5309',
expiryFrom: '2017-01-01',
expiryTo: '2019-01-01'
},
{
id: getId(),
firstName: 'Roger',
lastName: 'Green',
email: 'green@inklings.com',
phoneNumber: '867-5309',
expiryFrom: '2017-01-01',
expiryTo: '2019-01-01'
}
];
そしたら、ContactDetail で扱えるようにします。
<template>
<require from="./date-range-picker"></require>
<!-- 中略 -->
<div class="form-group row">
<label class="col-sm-3 col-form-label">Expiry Period</label>
<div class="col-sm-9">
<date-range-picker start-date.bind="contact.expiryFrom" end-date.bind="contact.expiryTo"></date-range-picker>
</div>
</div>
4. au run
する
これで準備完了です。
Aurelia を起動すれば、「有効期限」が追加され、Date Range Picker で扱えるようになっています。
$ au run
もし上記で起動できなければ au run --watch
を試してください。
http://localhost:3000/ にアクセスすると、以下のようになっているはずです。
これで完了です。お疲れ様でした。
おわりに
これで Aurelia で Date Range Picker を扱えるようになりました。
これがあれば Datepicker を2つ使ったまどろっこしい日付範囲選択から脱却できますね。
もし Date Range Picker を日本語化したい場合は、以下の記事を参考にすると良いと思います。
コピペで動く。bootstrap-daterangepickerの導入と日本語化
それでは、良い Aurelia 生活を。
-
前はチュートリアルなかった気がしたんですけど、少し見ない間にどんどん変わっていきますね。さすが 未来志向フレームワーク。 ↩