LoginSignup
3

More than 5 years have passed since last update.

labelのforの対象は後から追加されても有効

Last updated at Posted at 2015-02-21

label要素のfor属性で、対象となるinput要素のid属性を指定した時、その対象は後からDOMツリーに差し込まれたものでも有効になります。

こんなんで検証しました。

label-for.html
<!doctype html>
<button onclick="removeInput()">Remove input</button>
<button onclick="insertInput()">Insert input</button>

<label for="input">label</label>
<input id="input">

<script>
inputs = document.getElementsByTagName("input");
function removeInput() {
    console.info(inputs.length, inputs);
    for (var l = inputs.length, i = l - 1; i >= 0; i--) {
        var input = inputs[i];
        input.parentNode.removeChild(input);
    }
}
function insertInput() {
    console.info(inputs);
    var input = document.createElement("input");
    input.id = "input";
    document.body.appendChild(input);
}
</script>

「Remove input」ボタンを押してinputを削除した後に「Insert input」ボタンを押してDOMツリーに挿入しても、labelをクリックすると追加されたinputにフォーカスが当たります。

でなんなの、便利でよかったね? という話に見えるかも知れませんが、カスタムエレメントを作る時に気を付けることが増えます。似たようなインターフェイスの要素を作る時は、(MutationObserverとかで)DOMツリーを監視して、後から追加される要素にも対応できるようにしておいた方が、ユーザー(タグを書く人)の期待に沿うことが多いでしょう。

もちろん、こういう監視がたくさん生まれてるとパフォーマンスが心配になってきますね。だから、現実的には「後から追加された要素にも対応する」フラグの属性を定義して、デフォルトでオフにしておくのがいいかも知れません。


余談ですが、このような「後からの追加を監視するか否か」という状態を両方持つ物を僕達はよく知っています。DOMのNodeListです。

Node.chideNodesDocument.getElementsByTagName()なんかで取得したNodeListは後からの追加を監視しているので、DOMツリーの変更に応じて動的に内容が変わります(なので削除しながら順に処理する場合なんかは最初じゃなくて最後から処理する必要があったりする)。
一方でDocument.querySelectorAll()で返すNodeListは監視しません。例えばvar divs = document.querySelector("div")NodeListを取得した後に、divを足したり追加したりしても、divs変数の内容は変わりません。

そしてこの二つ、区別するAPIがありません……おっと愚痴になってしまいました。

のでまあ、後から監視しなくても「完全に期待に反している」わけではないのでまあいいかなと思います。

NodeListの「後からのDOMツリーの変更への対応」はliveコレクションか否か、ということで例えばMDNに載っています:https://developer.mozilla.org/ja/docs/Web/API/NodeList

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3