lightning:input の DatePicker は入力可能な日を制限できない場合がある

[[祝GA] lightning:input の DatePicker は入力可能な日を制限できる](https://qiita.com/nabe52602946/items/0e5a8a30587bf025db43) という投稿をしておきながら、「お前は何を言ってるんだ？」という気がしなくもないですが、気付いてしまったのでメモしておきます:disappointed_relieved:

# TL;DR
* どんな場合?
  * Datepicker と他のフォーム (例えば SUBMIT ボタン) があるような場合
  * Datepicker にテキスト入力して SUBMIT すると、範囲外の日付を入力できてしまう (下の gif 参照)
* 回避方法?
  * controller.js or helper.js で validation かなと

# 以下、時間がある人向け

## どんな場合?
以下の gif を見ていただくと早いかと思いますが、Datepicker の入力範囲外 (グレーアウト) の 7/25 という値は、キーボード入力できてしまうのですね。。。
「範囲外は入力できないはず」と安心しきって SUBMIT ボタンのハンドラでバリデーションをかけていないと、範囲外の値が流れていってしまうことになります:cold_sweat:
![before.gif](https://qiita-image-store.s3.amazonaws.com/0/43550/6710a458-e1e6-4d78-2c96-bb51839fd0e6.gif)

ちなみに、ソースは以下です。

```html
<!-- コンポーネント -->
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes">

    <!-- body -->
    <div class="row">
        <h2 class="header">Datepicker</h2>
        <lightning:input type="date" aura:id="datepicker1" name="input1"
                         label="Date field with min and max values"
                         value="2018-07-10" min="2018-07-05" max="2018-07-20" />
        
        <!-- SUBMIT ボタン -->
        <div class="gutter"/>
        <lightning:button variant="brand" label="SUBMIT" onclick="{! c.handleClick }"/>
        
        <!-- SUBMIT ボタンクリックで日付を表示する -->
        <div class="gutter"/>               
        <div aura:id="msg">
            You entered: <ui:outputDate aura:id="oDate" value="" />
        </div>
        
    </div>

</aura:component>
```

```javascript
// controller.js
({
  handleClick: function(cmp, event, helper) {
    // Datepicker の日付を取得して
    const value = cmp.find("datepicker1").get("v.value");
    // outputDate にセットする
    cmp.find("oDate").set("v.value", value);
  }
})
```

```css
// style.css
.THIS {
    background-color: white;
    margin: 5rem;
    height: 25rem;
    padding: 2rem;
}

.THIS .gutter {
    margin-top: 2rem;
}
```

## 回避方法

`lightning:inpu type="date"`の属性でそれらしいものが見つからなかったので、地道にハンドラ (controller.js or helper.js) 内で validation が手っ取り早いかなと思います。

日付については [moment.js](https://momentjs.com/) (v2.22.2) のお世話になります。`moment.min.js 16.4k` を右クリックで保存して、静的リソースに `momentjs` のように入れました。

挙動はシンプルに「max を超えている場合は何もしない」ことにしました。

```html
<!-- コンポーネント -->
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes">
    <!-- lib -->
    <ltng:require scripts="{!$Resource.momentjs}" />
    
    <!-- body -->
    <div class="row">
        <h2 class="header">Datepicker</h2>
        <lightning:input type="date" aura:id="datepicker1" name="input1"
                         label="Date field with min and max values"
                         value="2018-07-10" min="2018-07-05" max="2018-07-20" />
        
        <!-- SUBMIT ボタン -->
        <div class="gutter"/>
        <lightning:button variant="brand" label="SUBMIT" onclick="{! c.handleClick }"/>
        
        <!-- SUBMIT ボタンクリックで日付を表示する -->
        <div class="gutter"/>               
        <div aura:id="msg">
            You entered: <ui:outputDate aura:id="oDate" value="" />
        </div>
        
    </div>

</aura:component>
```

```javascript
// controller.js
({
  handleClick: function(cmp, event, helper) {
    // 説明簡略化のため、max の値をここでも定義
    const maxDateObj = moment("2018-07-20");
    // 入力された日付を moment にセット
    const inputObj = moment(cmp.find("datepicker1").get("v.value"));
    
    // max を超えていないか判定
    if (maxDateObj.diff(inputObj) < 0) {
      // max 以降の日付が入力された場合、何もしない
      return;
    }
        
    // max 以内の日付であれば、反映する
    cmp.find("oDate").set("v.value", inputObj.format("YYYY-MM-DD"));
  }
})
```

![after.gif](https://qiita-image-store.s3.amazonaws.com/0/43550/7430606a-71e3-81c1-24b9-b9b1fe7c9d25.gif)

2018-07-25 を入力した場合は、SUBMIT ボタン下の `You entered:` に反映されないことが確認できました。 

# まとめ
max 以降の日付が入力された場合の挙動を制御することができました。min についても同様です。
将来的に今回のような部分までケアされると良いですね:sweat_smile:

### 蛇足
本投稿を書きながら思ったのですが業務では
「範囲外が入力された時点で `SUBMIT` ボタンを非活性にする」
などという要件も考えられますね。。。

Datepicker からフォーカスが外れた (onblur) 場合と、値が更新された場合 (onchange) を活用すれば実現できるのですが・・・長くなってしまったので、余力があればまたいつか:flushed: