HTML5なら外部ライブラリを利用しないでリアルタイム入力チェック出来る

リアルタイム入力チェックは今のWEBページでは割りと標準化されつつあるけど、
ライブラリを選定したり、画面の表示を考えたりと何かと面倒。

HTML5の機能で追加されたバリデーション機能を利用すればそういった煩わしさから開放されるのでは？
と思いたち、外部ライブラリを一切使わずにリアルタイム入力チェックを実装してみた。

## コード

```html
<section>
    <form id="sampleForm">
        <label>
            半角英数字以外を入力してみよう
            <input
                type="text" id="input" placeholder="半角英数字で入力"
                pattern="^[0-9A-Za-z]+$" required>
        </label>
        <button type="submit" id="submit">送信</button>
    </form>
</section>

<script>
"use strict";
var form   = document.getElementById("sampleForm"),
    input  = document.getElementById("input"),
    submit = document.getElementById("submit");

input.addEventListener("input", function() {
    if (!input.value) {
        input.setCustomValidity("");
        submit.click();
        return;
    } else if (false === form.checkValidity()) {
        input.setCustomValidity("半角英数字以外の値が入力されました。");
        submit.click();
        return;
    }
    input.setCustomValidity("");
});
</script>
```

## 何をしているか？

- inputボックスに入力があるたびに、formの妥当性を`form.checkValidity()`を見て検証
- 検証結果が`false`だったらformをsubmitしてブラウザのバリデーションを実行
- `setCustomValidity`を利用して独自のメッセージを設定

### ちょっとハマった

formのsubmitを行うとき、`form.submit()`で実行出来るだろうと思っていたのだが、
`Uncaught TypeError: Property 'submit' of object #<HTMLFormElement> is not a function`
と言われてしまう（chromeのコンソールの場合）。

これはform中にsubmit要素を持ったbuttonがあるため、formにsubmitプロパティが提供されなくなってしまったためだ。
そこでsubmitボタンを削除して、`form.submit()`してみたが、今度はHTML5のバリデーションが実行されずにリクエストが送信されてしまった。

どうしたものかと思い、submitボタンを再度つけて、`submit.click()`でプログラム中からsubmitボタンをクリックしてあげることで解決した。

仕様を読んでいないので予測なのだけど、
上記のことから、HTML5のバリデーションはsubmitボタンのclickイベントから起動しているのではないのかな？

## まとめ

とても手軽にリアルタイム入力チェックが実装出来ますね。
実際の入力値のチェックはサーバサイドで行うものですし、
HTML5に対応していないブラウザは気にしない！と判断してシステムを作る場合、有効に活用出来るような気がしています。

# まとめを書いた後に実用を兼ねて機能を強化してみた（追記）

そういえば、復数入力欄があるのが普通だよなと思って実用を兼ねたコードを書いてみた

## 実用を考えたコード

```html
<meta charset="utf8">

<section>
    <form id="sampleForm">
        <label>
            半角英数字以外を入力してみよう
            <input
                type="text" class="validate" id="input" placeholder="半角英数字で入力"
                pattern="^[0-9A-Za-z]+$" required data-validity-msg="半角英数字のみで入力して下さい。">
        </label><br>
        <label>
            メールアドレスしかダメです
            <input
                type="email" class="validate" id="email" placeholder="メールアドレスを入力"
                required data-validity-msg="メールアドレスの形式で入力して下さい。">
        </label><br>
        <button type="submit" id="submit">送信</button>
    </form>
</section>
<script src="html5_validation.js">
```

```js:html5_valisation.js
(function() {"use strict";
/**
 * インプットボックスにvalidateイベントを設定
 */
function setValidate(e) {
    var input = e.target;

    // インプットボック全てにdisabled属性を付与後、
    // イベントのあった要素のdisabled属性を削除してvalidate対象を限定する
    elementsToAttribute(input_boxes, "disabled", "", function() {
        input.removeAttribute("disabled");
        input.setCustomValidity("");

        if (true === input.hasAttribute("required") && !input.value) {
            submit.click();
        } else if (false === input.checkValidity()) {
            input.setCustomValidity(input.getAttribute("data-validity-msg"));
            submit.click();
        }

        elementsOutAttribute(input_boxes, "disabled");
    });
}

/**
 * 要素のリスト全てに属性を追加する
 */
function elementsToAttribute(elements, attr, val, cb) {
    for (var i=0; i<elements.length; ++i) {
        elements[i].setAttribute(attr, val);
    }
    if (cb) cb();
}

/**
 * 要素のリスト全から属性を削除する
 */
function elementsOutAttribute(elements, attr, cb) {
    for (var i=0; i<elements.length; ++i) {
        elements[i].removeAttribute(attr);
    }
    if (cb) cb();
}

var submit      = document.getElementById("submit"),
    input_boxes = document.querySelectorAll(".validate");

for (var i=0; i<input_boxes.length; ++i) {
    try {
        input_boxes[i].addEventListener("input", setValidate);
    } catch (e) {
        console.log(e);
    }
}
// end proc.
})();
```

## 実用を兼ねて変えたところ

- カスタムvalidityメッセージを`data-validity-msg`属性に設定するようにした
- 入力した要素のみに`validate`を機能させたかったのでformの入力要素に`disabled`属性を与えた後に、入力のあった要素から`disabled`要素を削除するようにした。

## 実用を考えてみてのまとめ

更にケースを考慮すると、`min`、`max`、`maxlength`などに対応するコードも必要になり、手軽感が更になくなります！！
全然気軽に書けないですね；；これならライブラリを活用したほうが…