スポンサーリンク

JavaScriptの動かないコード (中級編) cloneNodeで選択状態が変わるエラー


以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)

<input type="button" onClick="f()"
 value="「cが選択済みでチェック有りの状態」をコピー" >

<div id="div0">
	<div id="div1">
		<!-- セレクトボックス -->
		<select id="select1">
			<option>a</option>
			<option>b</option>
			<option selected>c</option>
		</select>
		<!-- チェックボックス -->
		<input type="checkbox" id="check1" checked="checked">
	</div>
</div>

<script language="JavaScript">

function f()
{
	// trueを指定して,子ノードごとコピーする
	var e_div = div1.cloneNode(true);
	e_div.id = "div2";
	e_div.getElementsByTagName("select")[0].id = "select2";
	e_div.getElementsByTagName("input")[0].id = "check2";

	// コピーしたノードを追加
	div0.appendChild( e_div );

	// 「2」と表示
	alert( select2.selectedIndex ] );
	// 「c」と表示
	alert( select2.options[ select2.selectedIndex ].value );
	// 「true」と表示
	alert( check2.checked );
}

</script>



答え



IEでは 「0」,「」(空白),「true」 と表示され,
Firefoxでは 「2」,「c」,「true」 と表示される。 


しかも,もし事前に操作を行なって選択状態を変化させた場合,セレクトボックスの挙動は上記の通りのままだが,チェックボックスについては,FFでは直前の選択状態がそのままコピーされる。


挙動をまとめると,下記のようになる。

// FF:事前操作にかかわらず2(デフォルト値)
// IE:事前操作にかかわらず0(一番上にリセット)	
alert( select2.selectedIndex );

// FF:事前操作に依存して直前の状態をコピー
// IE:事前操作にかかわらずtrue(デフォルト値)
alert( check2.checked );


セレクトボックスについては,コピー前に何を選択していようと,コピー後の状態には影響しない。

一方チェックボックスの方は,FFの場合,コピー前の状態がコピー後に影響する。(このあたり,一貫性が欠けているようにも思える。)


こういったブラウザ間での挙動の違いを吸収するためには,コピー時に選択状態を含めて初期化・指定しておくしかない。

下記URLを参照。

cloneNodeでコピーすると選択状態がデフォルトに戻ってしまう対策 [JavaScript, Tips]
http://programming-magic.com/?id=59

なおIEでは,冒頭のコードでセレクトボックスのvalueを出そうとすると 「」(空白)になる。

こうなる原因は,option 要素の属性で value="〜" の指定を省略しているためだ。
この場合,FFはoption要素の内容をvalueとみなすのに対し,IEはvalue無しとみなす。


しかし,HTML4.01のドキュメントを見ると,本来はFirefoxの挙動が正しいという事が分かる。

HTML 4.01 仕様書邦訳概説
http://www.asahi-net.or.jp/~SD5A-UCD/...


OPTION要素の属性定義

value = cdata [CS]
この属性は、当該コントロールの初期値を指定する。この属性が設定されていない場合、初期値はOPTION要素の内容となる。


対策としては,option要素には明示的にvalue属性をセットするように心がける事になるだろう。