vaadin-date-picker の拡張 (独自コンポーネント作成)

Vaadin Flow (beta3) を勉強しています。その試行錯誤の記録です。

 vaadin-date-picker では日付書式を変更するのに、JavaScripti18n.formatDate関数や i18n.parseDate 関数を書く必要があるようです。面倒なので、属性で指定できるように独自のカスタムコンポーネントを作ってみました。

Java側では、DatePickerを継承するだけ。

@Tag("ex-date-picker")
@HtmlImport("src/component/ex-date-picker.html")
public class ExDatePicker extends DatePicker {
}

HTML(src/component/ex-date-picker.html)では、コンポーネントにプロパティlocale, format, pickerTitle を新設し、それを元に i18n オブジェクトを構築するようにしました。
とりあえず日本語しか対応してません。

<link rel="import" href="/frontend/bower_components/vaadin-date-picker/vaadin-date-picker.html"/>
<script src="/frontend/bower_components/momentjs/2.21.0/moment.js"></script>
<script src="/frontend/bower_components/momentjs/2.21.0/locale/ja.js"></script>
<script src="/frontend/bower_components/moment-jdateformatparser/1.0.2/moment-jdateformatparser.js"></script>
<dom-module id="ex-date-picker">
  <script>
    class ExDatePicker extends Vaadin.DatePickerElement {
      static get is() {
        return 'ex-date-picker'
      }
      static get properties() {
        return {locale: String, format: String, pickerTitle: String};
      }
      static get observers() {
        return ['_setupI18n(locale, format, pickerTitle)'];
      }
      ready() {
        super.ready();
      }
      _setupI18n(locale, format, pickerTitle) {
        // TODO: 日本語しか対応してない。ロケール毎に i18n オブジェクトやデフォルトフォーマットを切り替える必要がある
        const pickerLocale = locale || 'ja';
        const javaDateFormat = format || 'yyyy/MM/dd';
        const pickerTitleFormat = pickerTitle || '{fullYear}年 {monthName}';
        const dateFormat = moment().toMomentFormatString(javaDateFormat);
        this.i18n = {
          week: '週',
          calendar: 'カレンダー',
          clear: 'クリア',
          today: '本日を設定',
          cancel: 'キャンセル',
          firstDayOfWeek: 0,
          monthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
          weekdays: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],
          weekdaysShort: ['日', '月', '火', '水', '木', '金', '土'],
          formatDate: function(dateInputObject) {
            return moment(dateInputObject).locale(pickerLocale).format(dateFormat);
          },
          formatTitle: function(monthName, fullYear) {
            return pickerTitleFormat.replace('{fullYear}', fullYear).replace('{monthName}', monthName);
          },
          parseDate: function(dateString) {
            const date = moment(dateString, dateFormat).locale(pickerLocale).toDate();
            return {day: date.getDate(), month: date.getMonth(), year: date.getFullYear()};
          }
        };
      }
    }
    customElements.define(ExDatePicker.is, ExDatePicker);
  </script>
</dom-module>

ここで使用している moment.js などは、mavenで次の依存を追加して導入しています。

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>momentjs</artifactId>
            <version>2.21.0</version>
        </dependency>
        <dependency>
            <groupId>org.webjars.bower</groupId>
            <artifactId>moment-jdateformatparser</artifactId>
            <version>1.0.2</version>
        </dependency>

これで部品ができました。
次のように使います。

<ex-date-picker format="yyyy年M月d日" locale="ja"></ex-date-picker>

これで日付を日本語で表示できました。

f:id:yoshiob:20180406152651p:plain
vaadin-date-picker拡張コンポーネント

こんな感じでカスタムコンポーネントを作れることがわかりました。
それにしても vaadin-date-picker のUXはとても優れていますね。