Fieldオブジェクト
【抜粋】 var Field = { clear: function() { for (var i = 0; i < arguments.length; i++) $(arguments[i]).value = ''; }, focus: function(element) { $(element).focus(); }, present: function() { for (var i = 0; i < arguments.length; i++) if ($(arguments[i]).value == '') return false; return true; }, select: function(element) { $(element).select(); }, activate: function(element) { element = $(element); element.focus(); if (element.select) element.select(); } }
入力フィールドを扱うオブジェクトです。主に、テキストボックス、テキストエリア、パスワード、ファイル送信フォームが対象となります(ただし、ファイル送信フォームの入力値は、スクリプトからは読み取り専用なので、clearメソッドは無効です)。例は最後にまとめます。
clearメソッド
引数の要素(ID指定可)すべての入力値をクリアします。
focusメソッド
引数の要素(ID指定可)にカーソルを移動します。
presentメソッド
引数の要素(ID指定可)すべての入力値が空でない場合にtrue、そうでない場合はfalseを返却します。prototype.jsにおける入力項目チェックに関する機能は、このpresentメソッドくらいです。他はありません・・・。
selectメソッド
引数の要素(ID指定可)の入力値を全選択します。
activateメソッド
引数の要素(ID指定可)にカーソルを移動後、要素にselectメソッドがあれば実行します。他のメソッドと違い、入力フィールド以外(チェックボックス等)も扱うことができます。
【例】 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> <script> <!-- function check(fm){ if(Field.present(fm.TEXT, fm.PASS, fm.FILE, fm.AREA)){ alert("すべて入力済み"); }else{ alert("未入力あり"); } } //--> </script> </head> <body> <form onsubmit="return false;"> <input type="text" name="TEXT" value="TESTBOX"/><br/> <input type="password" name="PASS" value="PASS"/><br/> <input type="file" name="FILE"/><br/> <textarea name="AREA">TEXTAREA TEXTAREA</textarea><br/> <input type="checkbox" name="CHECK"/><br/> <button onclick="Field.clear(this.form.TEXT, this.form.PASS);"> CLEAR TEXTBOX & TEXTAREA</button><br/> <button onclick="Field.focus(this.form.FILE);">FOCUS INPUT_FILE</button><br/> <button onclick="check(this.form);">CHECK</button><br/> <button onclick="Field.select(this.form.AREA);">SELECT TEXTAREA</button><br/> <button onclick="Field.activate(this.form.CHECK);">ACTIVATE</button><br/> <br/> <input type="reset"/><br/> </form> </body> </html>
id属性指定のほうがコードは簡潔になりますが、現実的にはname属性指定が多いと思うのでこうしました。個人的にはform.elements['name']で指定するほうが好みですが、こちらは簡潔にするため名前で直接指定してます^^;
Formオブジェクト
【抜粋】一部省略 var Form = { serialize: function(form) { var elements = Form.getElements($(form)); var queryComponents = new Array(); for (var i = 0; i < elements.length; i++) { var queryComponent = Form.Element.serialize(elements[i]); if (queryComponent) queryComponents.push(queryComponent); } return queryComponents.join('&'); }, (省略) reset: function(form) { $(form).reset(); } }
Formオブジェクトは、フォームの入力要素を扱うためのメソッドを備えます。メソッドは引数にフォーム要素(ID指定可)を取ります。
serializeメソッド
【抜粋】 serialize: function(form) { var elements = Form.getElements($(form)); var queryComponents = new Array(); for (var i = 0; i < elements.length; i++) { var queryComponent = Form.Element.serialize(elements[i]); if (queryComponent) queryComponents.push(queryComponent); } return queryComponents.join('&'); },
引数のフォーム要素(ID指定可)の入力要素すべてを、サーチデータとして使用できる文字列に変換するメソッド。「Ajax.Requestでのフォームデータ送信サンプル(postbodyへの設定) - Backstage of theater.js」でも触れましたが、Ajax.Request等のparametersプロパティやpostBodyプロパティ*1にフォーム内容を設定する場合に威力を発揮します。
Form.getElementsは、フォームの入力要素を格納した配列を取得するメソッドです。後述します。
Form.Element.serializeは後述Form.Elementオブジェクトのメソッドで、引数の要素を「name=value」形式の文字列にし、URIエンコードして返却します。処理の実際は、更に後述のForm.Element.Serializersオブジェクトのメソッドで行われています。
対象とするタグと処理は以下になります。(※すべてURIエンコードする)
タグ | type | 文字列化処理 |
---|---|---|
input | submit hidden password text |
"(name属性)=(value属性)"で返却 |
input | checkbox radio |
チェックされている場合"(name属性)=(value属性)"で返却。 複数チェック時は同一name文字列を「&」で繋げる |
textarea | - | "(name属性)=(value属性)"で返却 |
select | select-one (multiple未指定) |
"(name属性)=(選択されたオプションのvalue属性)"で返却 |
select | select-multiple (multiple指定) |
"(name属性)=(選択されたオプションのvalue属性)"で返却。 複数選択時は同一name文字列を「&」で繋げる |
inputタグのうち、以下は対象外です。
対象外type | button, file, image, reset |
---|
他はともかく、buttonが対象外という点は注意が必要です。
また、name属性を指定しないと処理対象にならないので注意してください。id属性指定では有効になりません。
【例】 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> </head> <body> <form onsubmit="return false;"> <input type="text" name="TEXT" value="テキストボックス"/> <textarea name="TEXTAREA">テキストエリア</textarea> <input type="checkbox" name="CHECKBOX" value="CHECK1" checked/> <input type="checkbox" name="CHECKBOX" value="CHECK2" checked/> <input type="radio" name="RADIO" value="RADIO1" checked/> <input type="radio" name="RADIO" value="RADIO2"/> <select name="SELECT"> <option value="OPTION1">オプション1</option> <option value="OPTION2" selected>オプション2</option> <option value="OPTION3">オプション3</option> <option value="OPTION4">オプション4</option> </select> <select size="3" name="SELECTSIZE" multiple> <option value="OPTION1" selected>オプション1</option> <option value="OPTION2">オプション2</option> <option value="OPTION3" selected>オプション3</option> <option value="OPTION4">オプション4</option> </select> <input type="hidden" name="HIDDEN" value="隠しパラメータ"/> <input type="submit" name="SUBMIT" value="SUBMIT"/> <input type="file" name="FILE"/><!--対象外--> <input type="button" name="BUTTON" value="BUTTON"/><!--対象外--> <br/><br/> <button onclick="Element.update('test', Form.serialize(this.form));">TEST</button> <button onclick="Element.update('test', decodeURIComponent($('test').innerHTML));"> DECODE</button> </form> <div id="test"></div> </body> </html>
【上記例の実行結果】TESTボタン押下時
TEXT=%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9&CHECKBOX=CHECK1&CHECKBOX=CHECK2&RADIO=RADIO1&HIDDEN=%E9%9A%A0%E3%81%97%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF&SUBMIT=SUBMIT&TEXTAREA=%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A8%E3%83%AA%E3%82%A2&SELECT=OPTION2&SELECTSIZE=OPTION2
【上記例の実行結果】TESTボタン押下後、DECODEボタン押下時
TEXT=テキストボックス&CHECKBOX=CHECK1&CHECKBOX=CHECK2&RADIO=RADIO1&HIDDEN=隠しパラメータ&SUBMIT=SUBMIT&TEXTAREA=テキストエリア&SELECT=OPTION2&SELECTSIZE=OPTION2
「Ajax.Requestでのフォームデータ送信サンプル(postBodyへの設定) - Backstage of theater.js」の例も参照してください。
getElementsメソッド
【抜粋】 getElements: function(form) { form = $(form); var elements = new Array(); for (tagName in Form.Element.Serializers) { var tagElements = form.getElementsByTagName(tagName); for (var j = 0; j < tagElements.length; j++) elements.push(tagElements[j]); } return elements; },
引数のフォーム要素(ID指定可)の入力要素をすべて配列に格納して返却するメソッド。後述Form.Element.Serializersクラスのメソッドと同名のタグを抽出しています。対象タグは以下になります。
対象タグ | input, textarea, select |
---|
typeによる判定はここでは行っていないので、inputタグのtype="file"や"button"も対象となります。
【例】 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> <script> <!-- function test(fm){ //elementsに入力要素オブジェクトの配列を取得 var elements = Form.getElements(fm); //配列からnameの文字列を作成 var str = Object.inspect(elements.pluck("name")); //画面表示 Element.update('test', str); } //--> </script> </head> <body> <form onsubmit="return false;"> <input type="text" name="TEXT" value="テキストボックス"/> <textarea name="TEXTAREA">テキストエリア</textarea> <input type="checkbox" name="CHECKBOX" value="CHECK1" checked/> <input type="checkbox" name="CHECKBOX" value="CHECK2" checked/> <input type="radio" name="RADIO" value="RADIO1" checked/> <input type="radio" name="RADIO" value="RADIO2"/> <select name="SELECT"> <option value="OPTION1">オプション1</option> <option value="OPTION2" selected>オプション2</option> <option value="OPTION3">オプション3</option> <option value="OPTION4">オプション4</option> </select> <select size="3" name="SELECTSIZE" multiple> <option value="OPTION1" selected>オプション1</option> <option value="OPTION2">オプション2</option> <option value="OPTION3" selected>オプション3</option> <option value="OPTION4">オプション4</option> </select> <input type="hidden" name="HIDDEN" value="隠しパラメータ"/> <input type="submit" name="SUBMIT" value="SUBMIT"/> <input type="file" name="FILE"/> <input type="button" name="BUTTON" value="BUTTON"/> <br/><br/> <button onclick="test(this.form);">TEST</button> </form> <div id="test"></div> </body> </html>
【上記例の実行結果】TESTボタン押下時
['TEXT', 'CHECKBOX', 'CHECKBOX', 'RADIO', 'RADIO', 'HIDDEN', 'SUBMIT', 'FILE', 'BUTTON', 'TEXTAREA', 'SELECT', 'SELECTSIZE']
getInputsメソッド
【抜粋】 getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return inputs; var matchingInputs = new Array(); for (var i = 0; i < inputs.length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(input); } return matchingInputs; },
引数のフォーム要素(ID指定可)内の、inputタグ要素を格納した配列を返却するメソッド。第二引数のtypeNameでtype属性を、第三引数nameでname属性を指定できます。typeNameとnameを両方指定した場合は、どちらの条件も満たす要素が処理対象になります。
※(radioやcheckboxでない)inputタグに同一name属性が複数あるのは規則上違反。(参考サイト「http://chaichan.web.infoseek.co.jp/qa4000/qa4177.htm」) ただ、実際にはやってますが^^; 表組み等で大量のinputを扱う場合に、同一名にして要素の集合を処理すると楽なので・・・。
扱えるのはinputタグのみで、selectやtextareaタグは対象外です;;
【例】前述getElementsメソッドの例のtest関数を以下に入れ替えてください^^; function test(fm){ //elementsにinput要素の配列を取得 var elements = Form.getInputs(fm); //配列からnameの文字列を作成 var str = "INPUT:" + Object.inspect($A(elements).pluck("name")) + "<br/>"; //elementsにinput要素のtype="text"のみを取得 elements = Form.getInputs(fm, 'text'); //配列からnameの文字列を作成 str += "INPUT TYPE='TEXT':" + Object.inspect(elements.pluck("name")) + "<br/>"; //elementsにinput要素のname="BUTTON"のみを取得 elements = Form.getInputs(fm, null, 'BUTTON'); //配列からnameの文字列を作成 str += "INPUT NAME='BUTTON':" + Object.inspect(elements.pluck("name")) + "<br/>"; //画面表示 Element.update('test', str); }
【上記例の実行結果】TESTボタン押下時
INPUT:['TEXT', 'CHECKBOX', 'CHECKBOX', 'RADIO', 'RADIO', 'HIDDEN', 'SUBMIT', 'FILE', 'BUTTON']
INPUT TYPE='TEXT':['TEXT']
INPUT NAME='BUTTON':['BUTTON']
ちょっと気になったのは、typeNameとnameを無指定時はgetElementsByTagNameの結果がそのまま返却されるのですが、指定時はArrayオブジェクトが返却されます。なので、typeNameとnameを無指定時に、返却オブジェクトでArrayクラスメソッドを使いたい場合は、一度変換する必要があります。ま、変換すればいいだけの話ですが・・・。
disableメソッド
【抜粋】 disable: function(form) { var elements = Form.getElements(form); for (var i = 0; i < elements.length; i++) { var element = elements[i]; element.blur(); element.disabled = 'true'; } },
引数のフォーム要素(ID指定可)のすべての入力要素に対し、カーソルを外し、disableプロパティをtrueにする処理を行うメソッド。対象タグはForm.getElementsメソッドと同じです。
ただ、このメソッドがあるのなら、buttonタグも対象にしてほしかった気がします・・・。
例は次のenableメソッドにまとめます。
enableメソッド
【抜粋】 enable: function(form) { var elements = Form.getElements(form); for (var i = 0; i < elements.length; i++) { var element = elements[i]; element.disabled = ''; } },
前述disableメソッドの逆。引数のフォーム要素(ID指定可)のすべての入力要素に対し、disableプロパティを''(空文字)にする処理を行うメソッド。対象タグはForm.getElementsメソッドと同じです。
【例】 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> <script> <!-- function submitFunc(btn){ var fm = btn.form; fm.action = "test.htm"; fm.method = "get"; fm.submit(); Form.disable(fm); alert("SUBMITします"); } //--> </script> </head> <body> <form> <input type="text" name="TEXT" value="テキストボックス"/> <textarea name="TEXTAREA">テキストエリア</textarea> <input type="checkbox" name="CHECKBOX" value="CHECK1" checked/> <input type="checkbox" name="CHECKBOX" value="CHECK2" checked/> <input type="radio" name="RADIO" value="RADIO1" checked/> <input type="radio" name="RADIO" value="RADIO2"/> <select name="SELECT"> <option value="OPTION1">オプション1</option> <option value="OPTION2" selected>オプション2</option> <option value="OPTION3">オプション3</option> <option value="OPTION4">オプション4</option> </select> <select size="3" name="SELECTSIZE" multiple> <option value="OPTION1" selected>オプション1</option> <option value="OPTION2">オプション2</option> <option value="OPTION3" selected>オプション3</option> <option value="OPTION4">オプション4</option> </select> <input type="hidden" name="HIDDEN" value="隠しパラメータ"/> <input type="submit" name="SUBMIT" value="SUBMIT"/> <input type="file" name="FILE"/> <input type="button" name="BUTTON" value="BUTTON"/> <br/><br/> <button onclick="Form.disable(this.form);">DISABLE</button> <button onclick="Form.enable(this.form);">ENABLE</button> <input type="button" onclick="submitFunc(this);" value="SUBMIT"/> <!--これがBUTTONタグだと意味がない--> </form> </body> </html>
buttonタグ要素は対象フォーム内にありますが、disableメソッドの影響を受けません。これはちょっと困る気がします。disableメソッドが有用な場面として、ユーザが送信ボタンを押した時に、submit後にフォーム内容をdisable化することで、二重送信を防ぐというものがあります*2。 ただ、このときbuttonタグを使っていると、Form.disableメソッドは使えません。buttonタグはinput type="button"よりもカスタムがしやすいので、使用してる方も多いと思うのですが・・・。
後述するForm.Element.Serializersクラスを改造して、buttonタグを扱うようにするのも手だと思います。後述します。
findFirstElementメソッド
findFirstElement: function(form) { return Form.getElements(form).find(function(element) { return element.type != 'hidden' && !element.disabled && ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); }); },
引数のフォーム要素(ID指定可)の入力要素のうち、typeプロパティが'hidden'でなく、disabledプロパティがfalseまたは無指定で、タグがinputかselectかtextareaのものを一つ返却するメソッド。名前から「最初の」要素を返却しそうなものなのですが、そうではないです。。。 getElementsメソッドは、input>textarea>selectの順で要素を収集します。このため、select要素が先頭にあっても、後にinput要素があれば、そちらが返却されます・・・。
【例】 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> <script> <!-- function test(fm){ //取得した要素のname属性を画面表示 Element.update('test', Form.findFirstElement(fm).name); } //--> </script> </head> <body> <form onsubmit="return false;"> <select name="SELECT"> <option value="OPTION1">オプション1</option> <option value="OPTION2">オプション2</option> </select> <textarea name="TEXTAREA">テキストエリア</textarea> <input type="text" name="TEXT" value="テキストボックス"/> <br/><br/> <button onclick="test(this.form);">TEST</button> </form> <div id="test"></div> </body> </html>
【上記例の実行結果】 TEXT
テキストボックスを消すと「TEXTAREA」に、テキストエリアも消すと「SELECT」になります・・・。使用する場面が想定できない><; getElementsメソッドを改善する必要がある気がします・・・。(2006/09/12追記。とは言ったものの、すぐには代替案が見つかりません^^; 思いついたら追記します。)
focusFirstElementメソッド
【抜粋】 focusFirstElement: function(form) { Field.activate(Form.findFirstElement(form)); },
引数のフォーム要素(ID指定可)で、前述findFirstElementメソッドで取得した要素を選択状態にするメソッドです。これもやっぱり使用する場面が想定できません・・・。
【例】前述findFirstElementメソッドのtest関数を以下に置き換えてください^^; function test(fm){ //取得した要素のにカーソルを合わせる Form.focusFirstElement(fm); }
実行するとテキストボックスが選択されます。テキストボックスを消すとテキストエリアが、テキストエリアも消すとセレクトメニューが選択状態になります・・・。
resetメソッド
【抜粋】 reset: function(form) { $(form).reset(); }
引数のフォーム要素(ID指定可)の入力値をデフォルトの状態に戻すメソッド。
例は省略します。