Form.Elementオブジェクト
【抜粋】一部省略 Form.Element = { serialize: function(element) { (省略) }, getValue: function(element) { (省略) } }
inputタグ等の入力要素を扱うオブジェクト。Formオブジェクトと違い、form経由でなくても要素を扱えます。
serializeメソッド
【抜粋】 serialize: function(element) { element = $(element); var method = element.tagName.toLowerCase(); var parameter = Form.Element.Serializers[method](element); if (parameter) { var key = encodeURIComponent(parameter[0]); if (key.length == 0) return; if (parameter[1].constructor != Array) parameter[1] = [parameter[1]]; return parameter[1].map(function(value) { return key + '=' + encodeURIComponent(value); }).join('&'); } },
引数の入力要素(ID指定可)から、"(name属性)=(value属性)"の文字列を作成して返却するメソッド。selectタグでmultiple指定がある場合は、"(name属性)=(value属性1)&(name属性)=(value属性2)"のように「&」で繋げて返却します。複数の同名radioやcheckboxには対応していないので注意してください。
Form.Element.Serializersは、入力要素のタグと同じ名前のメソッドを備えています。これらのメソッドは、対応する入力要素を元に [(name属性), (value属性)] という配列を作成して返却します。selectタグでmultiple指定がある場合、返却する配列は [(name属性), [(value属性1), (value属性2), ・・・ ] ] となります。
これを元に、返却する文字列を作成しています。name、valueともにすべてURIエンコードされます。
【例】 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> <script> <!-- function test(element){ var str; if(element.length != null && element.type == null){ str = $A(element).collect(function(elem){ return Form.Element.serialize(elem); }).compact().join("&"); }else{ str = Form.Element.serialize(element); } Element.update('test', str); } //--> </script> </head> <body> <form onsubmit="return false;"> <input type="text" name="TEXT" value="テキストボックス"/><br/> <button onclick="test(this.form.TEXT);">TEST</button><br/> <br/> <input type="radio" name="RADIO" value="RADIO1" checked/> <input type="radio" name="RADIO" value="RADIO2"/><br/> <button onclick="test(this.form.RADIO);">TEST</button><br/> <br/> <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><br/> <button onclick="test(this.form.SELECTSIZE);">TEST</button><br/> <br/> <button onclick="Element.update('test', decodeURIComponent($('test').innerHTML));"> DECODE</button> </form> <div id="test"></div> </body> </html>
各「TEST」ボタンを押すと、直前の要素から文字列を作成して表示します。DECODEボタンで表示文字列をURIデコードします。test関数ではRADIOボタン用に処理を分岐しています。(判定ロジックはてきとーです^^;*1 )
Arrayクラスの追加メソッドを使っています。簡単に説明すると、要素の集合elementを配列化して、それぞれのserializeの結果を配列に格納し(collectメソッド)、そこからnulll(undefined)を除外(compactメソッド)した上で、既存joinメソッドで文字列化しています。
getValueメソッド
【抜粋】 getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); var parameter = Form.Element.Serializers[method](element); if (parameter) return parameter[1]; }
引数の入力要素(ID指定可)から、value属性の値を返却するメソッド。selectタグでmultiple指定がある場合は、値を格納した配列を返却します。こちらも複数の同名radioやcheckboxには対応していないので注意してください。
【例】前述serializeメソッドの例のtest関数を以下に変更してください^^; function test(element){ var value; if(element.length != null && element.type == null){ value = $A(element).collect(function(elem){ return Form.Element.getValue(elem); }).compact(); }else{ value = Form.Element.getValue(element); } Element.update('test', Object.inspect(value)); }
やっぱり、複数の同名radioやcheckboxにも対応してくれないと、使いにくい気がするのですが。。。
2006/09/13追記。改修案を作ろうと思いましたが、Form.Elementクラスのメソッドはprototype.js内の他の部分で使用されているため、メソッド上書きはちょっとやりにくいです。なので別のメソッドを追加することを検討してみました。
【改修案】追加メソッド serialize2 : function(element){ var retStr; element = $(element); if(element.length != null && element.type == null){ retStr = $A(element).collect(function(elem){ return this.serialize(elem); }.bind(this)).compact().join("&"); }else{ var tags; if(element.form){ tags = element.form.elements[element.name]; }else{ tags = document.getElementsByName(element.tagName); } if(tags.length != null && tags.length > 1 && tags.type == null){ retStr = tags.collect(function(tag){ return this.serialize(tag); }.bind(this)).compact().join('&'); }else{ retStr = this.serialize(element); } } return retStr; }, getValue2 : function(element){ var retVal; element = $(element); if(element.length != null && element.type == null){ retVal = $A(element).collect(function(elem){ return this.getValue(elem); }.bind(this)).compact(); }else{ var tags; if(element.form){ tags = element.form.elements[element.name]; }else{ tags = document.getElementsByName(element.tagName); } if(tags.length != null && tags.length > 1 && tags.type == null){ retVal = tags.collect(function(tag){ return this.getValue(tag); }.bind(this)).compact(); }else{ retVal = this.getValue(element); } } return retVal; }
引数elementはID指定、要素指定、要素集合指定に対応しています。ID、要素指定の場合は所属フォーム内(所属フォームがない場合はドキュメント全体)に同じ名前の要素があれば処理対象に加えます。要素集合指定時や同一名要素がある場合、返却結果はslelectタグのmultiple指定時と同じようになります(serialize2は「&」で連結された文字列、getValue2は配列。getValue2ではラジオボタンは通常、単一要素配列となります)。
formとnameで指定したい場合はdocument.(フォーム名).(要素名)*2等で指定してください。(実際は、form、name指定で値を取得できるほうが使い勝手がいいような気がしますが。そうすると完全に別物になってしまうのでパス^^;)
もしprototype.jsに追加する場合は、メソッド間の「,」付け忘れに注意してください。下の例のように別に定義するのもいいと思います。
【参考】改修案を用いた場合の例 <html> <head> <title></title> <script language="javascript" src="prototype.js" charset="utf-8"></script> <script> <!-- function test(element){ Element.update('test1', Form.Element.serialize2(element)); Element.update('test2', Object.inspect(Form.Element.getValue2(element))); } //メソッドの追加 Form.Element.serialize2 = function(element){ var retStr; element = $(element); if(element.length != null && element.type == null){ retStr = $A(element).collect(function(elem){ return this.serialize(elem); }.bind(this)).compact().join("&"); }else{ var tags; if(element.form){ tags = element.form.elements[element.name]; }else{ tags = document.getElementsByName(element.name); } if(tags.length != null && tags.length > 1 && tags.type == null){ retStr = $A(tags).collect(function(tag){ return this.serialize(tag); }.bind(this)).compact().join('&'); }else{ retStr = this.serialize(element); } } return retStr; } Form.Element.getValue2 = function(element){ var retVal; element = $(element); if(element.length != null && element.type == null){ retVal = $A(element).collect(function(elem){ return this.getValue(elem); }.bind(this)).compact(); }else{ var tags; if(element.form){ tags = element.form.elements[element.name]; }else{ tags = document.getElementsByName(element.name); } if(tags.length != null && tags.length > 1 && tags.type == null){ retVal = $A(tags).collect(function(tag){ return this.getValue(tag); }.bind(this)).compact(); }else{ retVal = this.getValue(element); } } return retVal; } //--> </script> </head> <body> <form onsubmit="return false;" name="FORMNAME"> <input type="text" name="TEXT" id="textID" value="テキストボックス"/><br/> <button onclick="test('textID');">TEST</button><br/> <br/> <input type="radio" name="RADIO" value="RADIO1" checked id="radioID"/> <input type="radio" name="RADIO" value="RADIO2"/><br/> <button onclick="test(document.FORMNAME.RADIO);">TEST</button> <button onclick="test($('radioID'));">TEST</button><br/> <br/> <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><br/> <button onclick="test(this.form.SELECTSIZE);">TEST</button><br/> <br/> <button onclick="Element.update('test1', decodeURIComponent($('test1').innerHTML));"> DECODE</button> </form> <div id="test1"></div> <div id="test2"></div> </body> </html>