読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

IE10 における placeholder 属性をもつ textarea 要素、または value 属性のない type="checkbox" の input 要素の clone に関するはまりどころ

JavaScript Internet Explorer Windows ストアアプリ

Windows ストアアプリで form 要素を含んだ Page コントロール を読み込もうとしたときに、期待しないレンダリング結果になった箇所があったのでちょっと調べてみた。 ちなみに期待しない結果になったのは以下の箇所。

  • textarea 要素 の placeholder 属性に指定していた値が、Page コントロールの読み込み後は textarea 要素に (プレースホルダーとしてではなく通常の入力値として) 入力されている状態になっていた
  • value 属性のないチェックボックス (type="checkbox" の input 要素) をチェックして form の送信を行うと、値が "on" にならずに送信されてしまった *1

この問題の原因を探っていくと IE10 のはまりどころっぽい箇所が見つかったので書き残しておく。 使用した IE のバージョンは RTM 版のもの (詳細は以下) なので、新しいバージョンだと修正されているかもしれない。

textarea 要素の placeholder 属性に指定した値は TextNode として textarea の子ノードに追加される

<textare id="ta" placeholder="プレースホルダーです"></textarea>

上記のような HTML があるとする。 textarea 要素の子ノードの個数は 0 個になるはずなのだが、IE10 だと子要素が 1 個存在し、その要素は "プレースホルダーです" というテキストを表す Text ノードだった。

var textareaElem = document.querySelector("#ta");
textareaElem.childNodes.length; // => 1 (IE10 の場合)
                                // => 0 (Firefox 16 beta, Chrome 22 の場合)
textareaElem.childNodes.item(0).nodeType; // => 3 (IE10 の場合; 3 は TextNode を表す)
textareaElem.childNodes.item(0).nodeValue; // => "プレースホルダーです" (IE10 の場合)

Page コントロールを読み込む際には、cloneNode メソッド による DOM 木のクローンが行われる。 上記のような子要素に TextNode をもつ textarea 要素がクローンされると子要素に Text ノードをもつ textarea 要素が生成されるわけで、子要素の Text ノードは textarea にデフォルトで入力されている値だとみなされてしまう。

というわけで、IE10 で placeholder 属性をもつ textarea 要素を DOM 木上で操作する場合は気を付けないといけない。 特に良い回避策は思いつかないので、とりあえず Page コントロール中で textarea の placeholder を使いたい場合は JavaScript で動的に placeholder プロパティに値を設定することにした。

value 属性のない type="checkbox" の input 要素を clone すると value が "" (空文字列) になる

前提

Checkbox state (type=checkbox) の input 要素の value は default/on モードである
4.10.7.1 States of the type attribute — HTML Standard

default/on モードというのは、value 属性がない場合に、value の値が "on" になるというもの。 なので、以下のように value 属性をもたないチェックボックスをチェックして form を送信した場合、"test-1=on" というようなクエリパラメータが付与される。

<form method="GET" action="http://example.com/.../">
  <input type="checkbox" name="test-1" />
  <input type="submit" />
</form>
input 要素を clone した場合、その value の値も clone 先に引き継がれる

The cloning steps for input elements must propagate the value, dirty value flag, checkedness, and dirty checkedness flag from the node being cloned to the copy.

4.10.7 The input element — HTML Standard
<input id="test-2" type="checkbox" />

上記のような HTML がある場合を考える。 この input 要素は value 属性をもっていないが、以下のように JavaScript 側で value プロパティを設定して clone すると、設定した value の値がクローン先の要素にも設定されている。

var inputElem = document.querySelector("#test-2");

// value を設定して clone すると, クローン先の value も設定した値と同じになる
inputElem.value = "testvalue";
inputElem.cloneNode().value; //=> "testvalue"

IE10 における問題

上に書いた前提は、IE10 でもそれぞれ単体だと満たされている。 しかしながら、value 属性もなく、JavaScript 側で value プロパティの設定もしていない input (type=checkbox) 要素をクローンした場合に、クローン先の input 要素の value は "" になってしまうという問題があった。 (本来は "on" になるはず。)

<input id="test-3" type="checkbox" />

このようなチェックボックスを以下のように clone すると、value の値が "" (空文字列) になる。

var inputElem = document.querySelector("#test-3");

inputElem.cloneNode().value; //=> "" (IE10 の場合)

なので、Page コントロール内のチェックボックスには、とりあえず何かしらの value 属性を書いておかないとはまる。

この記事とはあんまり関係ないけど WinJS の Page コントロールについては下記記事参照

Windows ストアアプリの話なので IE10 だけ気にしてる人には関係ない。

*1:本来、value 属性がなく value プロパティの設定もされていない checkbox は "on" という値で送信されるはず