Help us understand the problem. What is going on with this article?

Aurelia で Date Range Picker を使う

今回は Aurelia で Date Range Picker を使う方法について書いていきます。

最終的に、下図の「Expiry Period」のようになります。
日付を範囲選択したい場合に便利ですので、宜しければご覧ください。

20180712_160701.png

また、解説不要な人のために 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.

jQueryMoment.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 クラスなども適用できるってことですね。

src/date-range-picker.html
<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

いくつかのブロックに分けて解説するので、先に完成形を書いておきます。

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 しています。

src/date-range-picker.js
import { inject, bindable, bindingMode } from 'aurelia-framework';
import $ from 'jquery';
import moment from 'moment';
import 'daterangepicker';

次に宣言。
startDateendDate は双方向バインドする必要があるので bindingMode.twoWay を指定。
options は Date Range Picker のオプションを利用側から扱えるようにしています。オプションの詳細は Options で。

src/date-range-picker.js
@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 を使う場合によく見ますね。
owningViewstartDateendDate の変更監視メソッド内で attached 後かどうかを判定するために使います。

src/date-range-picker.js
  constructor(element) {
    this.element = element;
  }

  created(owningView) {
    this.owningView = owningView;
  }

次に attached です。

$.extend(true, {/* default */}, {/* override */}) の形で書いていますので、bind された options の値を優先させます。
また、startDateendDate は twoWay bind で渡された値を優先させています。

options の設定が終わったら、Date Range Picker の初期化。
値が反映された時のメソッドは apply(start, end) で定義してあります。

また、moment.HTML5_FMT.DATESpecial Formats を参考にしています。

src/date-range-picker.js
  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 している startDateendDate に設定しているので、この Custom Element の利用側の変数にも反映されます。

src/date-range-picker.js
  apply(startDate, endDate) {
    this.startDate = startDate.format(this.options.locale.format);
    this.endDate = endDate.format(this.options.locale.format);
  }

最後に startDateendDate の変更検知メソッド。
Aurelia では Observable Properties を使って変数の変更検知を行うことができますが、bind される変数も使えます。
ここでは、この Custom Element 外から値を変更された場合に Date Range Picker の選択範囲に反映されるようにしています。

ちょっと特殊なのは if (this.owningView.isAttached) ですね。
$(this.element).data('daterangepicker') は attached されていないと存在しないため、この判定を行っています。

src/date-range-picker.js
  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 も使っています。

src/date-range-picker.css
.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 を追加します。

src/web-api.js
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 で扱えるようにします。

src/contact-detail.html
<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/ にアクセスすると、以下のようになっているはずです。

20180712_160701.png

これで完了です。お疲れ様でした。

おわりに

これで Aurelia で Date Range Picker を扱えるようになりました。
これがあれば Datepicker を2つ使ったまどろっこしい日付範囲選択から脱却できますね。

もし Date Range Picker を日本語化したい場合は、以下の記事を参考にすると良いと思います。
コピペで動く。bootstrap-daterangepickerの導入と日本語化

それでは、良い Aurelia 生活を。


  1. 前はチュートリアルなかった気がしたんですけど、少し見ない間にどんどん変わっていきますね。さすが 未来志向フレームワーク。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした