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指定可)の入力値をデフォルトの状態に戻すメソッド。

例は省略します。

*1:Ajax.Request等のインスタンス生成時の引数optionsオブジェクトのプロパティ

*2:これを実現するためには、SUBMITボタンを使用するのではなく、例のようにonclickイベント内の関数で、formオブジェクトのsubmitメソッドを実行し、直後にformをdisable化する必要があります。submit前にdisable化するとform内容が送信不可になるので、SUBMITボタンは不適当です。