hifiveとjQuery UIを組み合わせる【バリデーション】
hifiveは業務システム開発に特化しているのでjQuery UIやBootstrapと組み合わせて使われることが多くなっています。そこで今回はよく使われるライブラリについて、その組み合わせ方を紹介します。
今回はバリデーションです。
デモコードについて
実際に動作するデモはJSFiddleにアップロードしてあります。入力して送信ボタンを押すとバリデーションが実行されます。
HTMLについて
HTMLは次のようになります。通常のHTMLと変わりません。
<form method="get" action="#" id="form1"> | |
<fieldset> | |
<legend>アンケート</legend> | |
<div> | |
<div>好きな食べ物を選択して下さい</div> | |
<input type="checkbox" value="1" name="food">和食 <input | |
type="checkbox" value="2" name="food">中華 <input | |
type="checkbox" value="3" name="food">イタリアン <input | |
type="checkbox" value="4" name="food">フレンチ <span | |
class="errorMsg"></span> | |
</div> | |
<br> | |
<div> | |
<div>タバコを吸っていますか?</div> | |
<div> | |
<input type="radio" value="yes" name="conf_tobacco">はい <input | |
type="radio" value="no" name="conf_tobacco">いいえ <span | |
class="errorMsg"></span> | |
</div> | |
<br> | |
<div>1日の喫煙本数</div> | |
<div> | |
<input type="text" name="count">本 <span class="errorMsg"></span> | |
</div> | |
</div> | |
</fieldset> | |
<p> | |
<fieldset> | |
<legend>ユーザ情報登録</legend> | |
<div> | |
<div>URL(任意)</div> | |
<input type="text" name="url"> <span class="errorMsg"></span> | |
</div> | |
<p> | |
<div> | |
<div>ユーザID ("hifive"以外を入力すると「入力されたユーザ名は既に使用されています」がエラーメッセージに表示されます)</div> | |
<input type="text" name="userid"> <span class="errorMsg"></span> | |
</div> | |
<div> | |
<div>パスワードを入力(8~12文字)</div> | |
<input type="password" name="pass"> <span class="errorMsg"></span> | |
</div> | |
<div> | |
<div>パスワードを再入力</div> | |
<input type="password" name="conf_pass"> <span | |
class="errorMsg"></span> | |
</div> | |
<br> | |
</fieldset> | |
<br /> | |
<input type="submit" value="送信" /> | |
</p> | |
</form> |
CSSについて
CSSはエラー時の色をつけるクラスなどを追加しています。
@charset "utf-8"; | |
#form1 { | |
border: 1px solid black; | |
padding: 15px; | |
} | |
.errorMsg { | |
color: red; | |
} | |
.strong { | |
font-weight: bold; | |
} | |
.rules { | |
border-collapse: collapse; | |
} | |
.rules td { | |
border: 1px solid black; | |
} |
JavaScriptについて
JavaScriptは長いので、幾つかに分けて紹介します。まず、hifiveのコントローラ化が完了した際の__readyイベントにてバリデーションの設定を行います。
this.$find('#form1').validate({ | |
// Submitイベントが実行された場合に、自動でバリデーションを実行 | |
onsubmit: true, | |
// フォーカスが当たった場合に現在のエラー内容を一旦クリア | |
focusCleanup: true, | |
// バリデーションルール | |
rules: { | |
food: { | |
required: true | |
}, | |
conf_tobacco: { | |
required: true | |
}, | |
count: { | |
required: { | |
depends: '[name="conf_tobacco"][value="male"]:checked' | |
}, | |
number: { | |
depends: '[name="conf_tobacco"][value="male"]:checked' | |
}, | |
min: { | |
param: 1, | |
depends: '[name="conf_tobacco"][value="male"]:checked' | |
}, | |
max: { | |
param: 999, | |
depends: '[name="conf_tobacco"][value="male"]:checked' | |
} | |
}, | |
lastname: { | |
required: true | |
}, | |
firstname: { | |
required: true | |
}, | |
email: { | |
required: true, | |
email: true | |
}, | |
url: { | |
url: true | |
}, | |
userid: { | |
required: true, | |
minlength: 6, | |
remote: '/exists' // useridをパラメータのキーにして、/existsに結果を問い合わせる (サーバは"true"または"false"の文字列を返す必要がある) | |
}, | |
pass: { | |
required: true, | |
rangelength: [8, 12] | |
}, | |
conf_pass: { | |
equalTo: '[name="pass"]' | |
}, | |
policy: { | |
required: true | |
} | |
}, | |
messages: { // エラー時に表示するメッセージ | |
food: { | |
required: '1つ以上選択して下さい。' | |
}, | |
conf_tobacco: { | |
required: '「はい」または「いいえ」のいずれかを選択して下さい' | |
}, | |
count: { | |
required: '「はい」を選択した場合は、喫煙本数を入力して下さい', | |
number: '本数は数字で入力して下さい', | |
min: '{0}以上の値を入力して下さい', | |
max: '{0}以下の値で入力して下さい' | |
}, | |
lastname: { | |
required: '姓を入力して下さい' | |
}, | |
firstname: { | |
required: '名を入力して下さい' | |
}, | |
email: { | |
required: 'メールアドレスを入力して下さい', | |
email: '正しいメールアドレスを入力して下さい' | |
}, | |
url: { | |
url: '正しいURLを入力して下さい' | |
}, | |
userid: { | |
required: 'ユーザIDを入力して下さい。', | |
minlength: '{0}以上で入力して下さい。', | |
remote: '入力されたユーザ名は既に使用されています' | |
}, | |
pass: { | |
required: 'パスワードを入力して下さい', | |
rangelength: '{0}以上{1}文字以下で入力して下さい' | |
}, | |
conf_pass: { | |
equalTo: 'パスワードが一致しません' | |
}, | |
policy: { | |
required: '同意される場合はチェックを入れて下さい' | |
} | |
}, | |
// エラーメッセージの表示先を指定する | |
errorPlacement: function(error, el) { | |
el.parent().children('.errorMsg').append(error); | |
}, | |
// エラーがある要素毎に実行するコールバック | |
showErrors: function(errorMap, errorList) { | |
this.defaultShowErrors(); | |
}, | |
// 入力項目でエラーがあったときに実行されるハンドラ | |
highlight: this.ownWithOrg(this.highLightArea), | |
// エラーが解消されたときに実行されるハンドラ, | |
unhighlight: this.ownWithOrg(this.unHighLightArea), | |
// validateのチェックが通り、submitが行われるときに実行するハンドラ | |
submitHandler: this.ownWithOrg(this.submitHandler), | |
// validateでエラーが1つでもあると実行されるハンドラ | |
invalidHandler: this.ownWithOrg(this.invalidHandler), | |
// 入力項目でエラーが解消されるたびに実行されるハンドラ | |
success: this.ownWithOrg(this.successHandler) | |
}); |
この際、入力チェックを行う際などのイベントハンドラも設定もします。this.ownWithOrgを使うことでhifiveのコントローラ自身を渡せるようになります。
// エラーがある要素毎に実行するコールバック | |
showErrors: function(errorMap, errorList) { | |
this.defaultShowErrors(); | |
}, | |
// 入力項目でエラーがあったときに実行されるハンドラ | |
highlight: this.ownWithOrg(this.highLightArea), | |
// エラーが解消されたときに実行されるハンドラ, | |
unhighlight: this.ownWithOrg(this.unHighLightArea), | |
// validateのチェックが通り、submitが行われるときに実行するハンドラ | |
submitHandler: this.ownWithOrg(this.submitHandler), | |
// validateでエラーが1つでもあると実行されるハンドラ | |
invalidHandler: this.ownWithOrg(this.invalidHandler), | |
// 入力項目でエラーが解消されるたびに実行されるハンドラ | |
success: this.ownWithOrg(this.successHandler) |
後は各イベントハンドラの実装になります。
// 入力項目でエラーがあったときに実行されるハンドラ | |
highLightArea: function(orgThis, el, error, errorClass) { | |
$(el).css('background-color', 'red'); | |
}, |
// エラーが解消されたときに実行されるハンドラ, | |
unHighLightArea: function(orgThis, el, error, errorClass) { | |
var $el = $(el); | |
$el.css('background-color', ''); | |
// 操作した要素が「1日の喫煙本数」テキストボックスでかつ、「たばこを吸っていますか」チェックボックスが「いいえ」の場合は、 | |
// 「1日の喫煙本数」テキストボックスのハイライトを除去する | |
if ($el.is('[name="conf_tobacco"]') && this.$find('[name="conf_tobacco"]:checked').val() === 'female') { | |
this.$find('[name="count"]').css('background-color', ''); | |
} | |
}, |
// validateのチェックが通り、submitが行われるときに実行するハンドラ | |
submitHandler: function(orgThis, form, ev) { | |
alert('FORMの内容をサーバに送信します。'); | |
form.submit(); | |
}, |
// validateでエラーが1つでもあると実行されるハンドラ | |
invalidHandler: function(orgThis, ev, validator) { | |
alert('入力内容に誤りがあります。'); | |
}, |
// 入力項目でエラーが解消されるたびに実行されるハンドラ | |
successHandler: function(orgThis, errMsgElement, inputElement) { | |
if (window.console) { | |
console.log('入力OK: '+ inputElement.name); | |
} | |
}, |
最後にチェックボックス、ラジオボタンのバリデーションについて別途実装します。
//「好きな食べ物を選択して下さい」のバリデーション | |
'[name="food"] click': function(context, $ct) { | |
// input[name="food"]の要素に対してバリデーションを実行する | |
$ct.valid(); | |
}, | |
//「1日の喫煙本数」テキストボックスのバリデーション | |
'[name="count"] focusout': function(context, $ct) { | |
// input[name="count"]の要素に対してバリデーションを実行する | |
$ct.valid(); | |
} |
$(function() { | |
h5.core.controller('body', { | |
__name: 'sample.plugin.validationSampleController', | |
__ready:function() { | |
// バリデーターにルールやメッセージ等を設定 | |
this.$find('#form1').validate({ | |
// Submitイベントが実行された場合に、自動でバリデーションを実行 | |
onsubmit: true, | |
// フォーカスが当たった場合に現在のエラー内容を一旦クリア | |
focusCleanup: true, | |
// バリデーションルール | |
rules: { | |
food: { | |
required: true | |
}, | |
conf_tobacco: { | |
required: true | |
}, | |
count: { | |
required: { | |
depends: '[name="conf_tobacco"][value="yes"]:checked' | |
}, | |
number: { | |
depends: '[name="conf_tobacco"][value="yes"]:checked' | |
}, | |
min: { | |
param: 1, | |
depends: '[name="conf_tobacco"][value="yes"]:checked' | |
}, | |
max: { | |
param: 999, | |
depends: '[name="conf_tobacco"][value="yes"]:checked' | |
} | |
}, | |
url: { | |
url: true | |
}, | |
// useridをパラメータのキーにして、/existsに結果を問い合わせる | |
// サーバは"true"または"false"の文字列を返す必要がある | |
userid: { | |
required: true, | |
minlength: 6, | |
remote: '/exists' | |
}, | |
pass: { | |
required: true, | |
rangelength: [8, 12] | |
}, | |
conf_pass: { | |
equalTo: '[name="pass"]' | |
}, | |
policy: { | |
required: true | |
} | |
}, | |
messages: { // エラー時に表示するメッセージ | |
food: { | |
required: '1つ以上選択して下さい。' | |
}, | |
conf_tobacco: { | |
required: 'はい、またはいいえを選択して下さい' | |
}, | |
count: { | |
required: '「はい」を選択した場合は、喫煙本数を入力して下さい', | |
number: '本数は数字で入力して下さい', | |
min: '{0}以上の値を入力して下さい', | |
max: '{0}以下の値で入力して下さい' | |
}, | |
url: { | |
url: '正しいURLを入力して下さい' | |
}, | |
userid: { | |
required: 'ユーザIDを入力して下さい。', | |
minlength: '{0}以上で入力して下さい。', | |
remote: '入力されたユーザ名は既に使用されています' | |
}, | |
pass: { | |
required: 'パスワードを入力して下さい', | |
rangelength: '{0}以上{1}文字以下で入力して下さい' | |
}, | |
conf_pass: { | |
equalTo: 'パスワードが一致しません' | |
} | |
}, | |
// エラーメッセージの表示先を指定する | |
errorPlacement: function(error, el) { | |
el.parent().children('.errorMsg').append(error); | |
}, | |
// エラーがある要素毎に実行するコールバック | |
showErrors: function(errorMap, errorList) { | |
this.defaultShowErrors(); | |
}, | |
// 入力項目でエラーがあったときに実行されるハンドラ | |
highlight: this.ownWithOrg(this.highLightArea), | |
// エラーが解消されたときに実行されるハンドラ, | |
unhighlight: this.ownWithOrg(this.unHighLightArea), | |
// validateのチェックが通り、submitが行われるときに実行するハンドラ | |
submitHandler: this.ownWithOrg(this.submitHandler), | |
// validateでエラーが1つでもあると実行されるハンドラ | |
invalidHandler: this.ownWithOrg(this.invalidHandler), | |
// 入力項目でエラーが解消されるたびに実行されるハンドラ | |
success: this.ownWithOrg(this.successHandler) | |
}); | |
}, | |
highLightArea: function(orgThis, el, error, errorClass) { | |
$(el).css('background-color', 'red'); | |
}, | |
unHighLightArea: function(orgThis, el, error, errorClass) { | |
var $el = $(el); | |
$el.css('background-color', ''); | |
// 操作した要素が「1日の喫煙本数」テキストボックスでかつ、「たばこを吸っていますか」チェックボックスが「いいえ」の場合は、 | |
// 「1日の喫煙本数」テキストボックスのハイライトを除去する | |
if ($el.is('[name="conf_tobacco"]') && this.$find('[name="conf_tobacco"]:checked').val() === 'no') { | |
this.$find('[name="count"]').css('background-color', ''); | |
} | |
}, | |
submitHandler: function(orgThis, form, ev) { | |
alert('FORMの内容をサーバに送信します。'); | |
form.submit(); | |
}, | |
invalidHandler: function(orgThis, ev, validator) { | |
alert('入力内容に誤りがあります。'); | |
}, | |
successHandler: function(orgThis, errMsgElement, inputElement) { | |
if (window.console) { | |
console.log('入力OK: '+ inputElement.name); | |
} | |
}, | |
//「好きな食べ物を選択して下さい」のバリデーション | |
'[name="food"] click': function(context, $ct) { | |
// input[name="food"]の要素に対してバリデーションを実行する | |
$ct.valid(); | |
}, | |
//「1日の喫煙本数」テキストボックスのバリデーション | |
'[name="count"] focusout': function(context, $ct) { | |
// input[name="count"]の要素に対してバリデーションを実行する | |
$ct.valid(); | |
} | |
}); | |
}); |
hifiveでもvalidation機能を提供していますが、使い慣れた方を採用するケースもあるでしょう。そうした時にはコールバックの管理などはhifiveで行うことで、よりメンテナンスしやすいバリデーション実装ができるようになります。
実際に動作するデモはJSFiddleにアップロードしてあります。お試しください。
コメントは受け付けていません。