のらねこの気まま暮らし

技術系だけど、Qiita向きではないポエムとかを書くめったに更新されないヤツ

HeimdallというjQuery/Zeptoで使えるFormValidatorを書いた話

温泉発火村#2に参加しましたという記事で紹介したライブラリの話をもうちょっと突っ込んで話します。

Synopsis

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="/js/heimdal.min.js"></script>
<script>
// validatorのインスタンスを生成
var heimdall = $.heimdall({
    "name"    : ["required", ["length", [1,  32]]],
    "age"     : ["required", "int"],
    "gender"  : ["required", ["select", ["male", "female"],
    "message" : [            ["length", [0, 256]]]
});

$('.form')
  .on('submit', function () {
    var result = heimdall.validate({
      "name": $('#input-name').val(), // みたいな感じでフォームのデータを{name: value, }でvalidateに渡す
      ...
    });
  
    if (result.has_error()) { // エラーがあったら ...
      $(this).trigger('invalid', [result]); // エラーだよってイベントのトリガ発火するとか。
    }
  })
  .on('invalid', function (e, result) {
    // エラーを表示するなり、アラートを出すなり、リダイレクトするなり。
  });

Heimdallがやること

  • データの制約(ルール)の定義と保持
  • 与えられたデータが制約に基づくものかの検証
  • すべてのデータが制約通りのものかどうかの判定

制約(ルール)の定義

言わずもがな、必須入力、数値入力、E-mail、電話番号その他もろもろ、入力フォームに応じ仕様と照合して「何が正しいデータなのか」を定義するもの。

この制約は、formのnameアトリビュート毎にArrayで制約を定義する。 制約は独自のものを定義することもできる。

heimdal.load_constraints('my_rule', function (value) {
  // `tamanegi`以外の入力は受け付けない
  return value === 'tamanegi' ? true : false;
});

より柔軟に仕様に対応することができ、またheimdallの拡張も可能。

デフォルトでは、

  • requires: 必須入力
  • length: 入力文字列の上限・下限を設定できる
  • select: 文字列の集合の中に含まれている文字列である
  • int: 整数値である

が定義されている。

与えられたデータが制約に基づくものかを検証

いわゆるバリデーションの機能。 与えるデータは、formのnameアトリビュートをキーとしたオブジェクトを期待する。

すべてのデータが制約通りのものかどうかの判定

バリデーションはその結果をResultのオブジェクトとして返す。 これはエラーの有無/エラーの内容を取得することができる。

これは主にForm上でユーザにエラーの内容を表示するために利用する、ことを想定している。

Heimdallの背景

そもそもなんで「ヘイムダル」なのか。北欧神話の神が由来で、巨人の軍勢がビフレストを渡ってアースガルズへ侵攻するのを知らせる、という門番の役割を持ってる、ということから。

WEBサイトのフォームは、CGIの時代から多くのパターンが考慮され、またサイトの仕様に密接に関連している。使い勝手もサイトによって千差万別。

「サーバ側で不適切なデータであれば弾けばいい」というものから、「よりユーザにわかりやすいように」と考慮されたリッチなフォームまで存在する。

2013年において、入力フォームはJavaScriptを用いて多くの場合において逐一サーバーにリクエストを投げなくても正しい/正しくないの判定を行うことができ、かつ柔軟に表示を切り替えるようになっている。それも、端末にさほど負荷をかけずに。(例外はあるけれど

しかし、その実装は非情に面倒でありバリデーションようにライブラリは多くあるけれど、なかなか僕の好みに合うライブラリがなかった。

  1. バリデーションの制約を拡張できる
  2. エラーが出た時にその事由を取得し、シームレスにUIへ伝達できる
  3. jQuery, Zeptoのどちらでもつかえること
  4. (僕個人としての)直感的なインターフェース

4つめは、単純に気持よくかけるかどうかなんですが・・・

Heimdallはこの辺を指標として実装しました。

Heimdallの目指すトコロ

正直、Heimdallには足りない機能がある。

  • formに入力されているデータの取得する機能
  • formにエラーを伝達しUIを更新する機能
  • 単体のinputに対するバリデーション

formとの連携は、悩んだ結果、Heimdallから外すことにした。formの構造や取得方法は、Heimdallに依存してしまう。汎用性を求めようとすれば、その分ソースが膨らむ。メンテナンスコストも。

なので、それは(formaize)https://github.com/rymizuki/jquery-formizeというライブラリに委譲した。

formizeの構造・機能を許容できるのなら、それによって簡単にデータの取得/更新が可能になる。

単体のinputに対するバリデーションは、今後の課題として今もなお検討中。 なかなか良いアイディが浮かばず悶々としている。

あとがきてきな

さて、なんでこんな記事を書いているかというと、@karupanerura に触発されたというのが一番の理由なんだけれど。

jQueryHTML5の登場で、リッチなUIの実装はそのハードルは大分下がった。 しかし、それでもまだ「全角数字のみを受け入れるフォーム」「どのinputが間違っているのかわからないエラー」等の実にイケてないフォームは未だ多くある。

わざわざサーバにリクエストしてページを遷移しなくても、そのフォーム、そのページ内でエラーをハンドルできるんだから、通信とか無駄に時間を取って、ユーザ体験を損ねているだけじゃね? って思うことは多々ある。

多々あるが、それでも「じゃあJSで書きなヨー」とは言えない。それなりにコストがかかるし、僕もやっぱりPerlで書いたほうが早いし楽だって思うから。

Heimdallしかり、formizeしかり、僕はそういうハードルを下げたいと思ってる。もっとお手軽に、もっと少ないコードで、もっと素早く実装できるようにしたい。

これらのライブラリは少なくとも僕がストレスに思っていた、あるいはコピペで済ませていたやつを集約して汎用化したものなので、まだまだ至らない点は多くあると思う。 それでも、こうして公開して、自分だったり自分以外の誰かに使ってもらって、コードに対する知見をためて、改善していくことができるのも、いまのWEBがあってこそ。Github万歳ヽ(^o^)丿

何が言いたいかというと、全角数字入力のフォームとかうざいし通信の待ち時間とかストレスでそういうフォームを撃滅したいので簡単に実装にできるようなプラグインのために試してIssueとかぷるりくとか投げたり投げられたりしてだせーWEBサイトを減らしていこうぜ!!!

Heimdall、よろしくお願いします。

――と、SYNOPSIS以降はガリレイドンナ見ながら書いてたのでおかしな文章になってるかもしれないけど、がんばって明日はfromizeの記事を書きたいな! サムライフラメンコ見て寝よう。