「DOMが取得できない」ときに読むといいかも。
細々と続けているこの開発者ブログも気がつけばJavaScriptの話題ばかりですね。
まぁ私しか更新しないので当然ですが(笑)あ、いや、私だけ暇だとかそういうんじゃないですから!
え~と、よくある、いいえ、よくありすぎる質問がいまだに頻繁に有りすぎるのでここらでまとめておこうかなと思います。
1.「getElementByIdで取得しているはずなのに取得できていません」とか、
2.「IEだと取得できるのに他のブラウザだと取得できません」とか、
3.「ここまでは取得できたんですが、ここから先が分かりません(?)」
上記のどれかに当てはまるならとりあえず以下の記事を参考にして欲しいですね。
1.「getElementByIdで取得しているはずなのに取得できていません」の場合
DOMツリーは構築されていますか?
DOM APIで操作する時、DOMツリーが構築される前に(要はページがロードされる前に)取得しようとするとnullが返ります。
nullに対してsetAttributeとかしてもそれは無駄なわけで、要素の取得にはDOMツリーの構築を待たなければいけないわけですよ。で、以下のコード。
window.onload = function()
{
var elm = document.getElementById(‘ID名’);
}
これで確実に取得できます。window.onloadでページのロードを待っているんですね。ページのロードが完了すれば、当然DOMツリーの構築も完了しているので、あとは取得し放題です(笑)これを逐一書くのが面倒な方は、ハンドラ関数を設定してそこから各処理を振り分けるのがよろしいかと。
あと、window.onloadだと重い画像の読み込みに時間がかかった場合、なかなか起動しないので、domReadyを使うのも一つの手ですね。Firefoxとかなら、
document.addEventListener(‘DOMContentLoaded’, listener, false);
みたいにハンドラ設定ができるので、より精密なタイミングで処理が出来ます。
IEとSafariは他のやり方が必要となります。詳細はググってみてください。
2.「IEだと取得できるのに他のブラウザだと取得できません」の場合
取得したID、実はname属性じゃないですか?
IE(7以前)では、getElementByIdではなんとname属性も取得できます。これはバグなんですがね。
というわけで、getElementByIdでnameから取得している場合、他のブラウザでは間違いなく動きません。
…まぁこの方法でやってる方は少ないでしょうが。
ちなみに、IE8ではこのバグは無くなり、ID属性しか取得できなくなっています。
3.「ここまでは取得できたんですが、ここから先が分かりません(?)」の場合
取得した要素から、さらに階層をたどっていくかもう一度APIで取得してみては?
例えば、var d = document.getElementById(‘hogehoge’)とかやって、id=”hogehoge”の要素を取得したとします。
そこから先、つまりその要素の中にある要素が取得できません、みたいな質問ですね。
この場合、取得した要素からたどっていく方法と、さらにAPIを使って取得する方法がありますね。
前者の場合、
d.firstChild //要素の最初のノードを取得
d.childNodes //子要素の配列
とかで取得できます。但し、この場合は直接の子要素しか取得できません。孫要素を取得する場合は、
d.childNodes[1].childNodes[2]…….
と、何度も繰り返さないといけません。さらに注意。
子要素は、何もエレメントノードだけとは限りません。
d.firstChildで取得した場合、始めの子要素を取得するんですが、ソースを見やすくするために適宜改行を入れている場合は(実際はほとんどそうでしょうが)、かなりの確率で改行部分を空のテキストノードとして取得する場合が多いです。その場合、当然TypeErorとなりますね。よって、そのノードがエレメントノードかどうかを判定してから次のステップに進むほうがベターです。
例えば、
var e = document.getElementById(‘hogehoge’).firstChild; //要素の始めの子要素を取得
while ( e.nodeType !== -1) //ノードがエレメントノードでない限りループする
{
if (!e)break; //要素が存在しなければループ終了。
e = e.nextSibling; //要素の次の兄弟要素を取得
}
とかやれば、確実に最初のエレメントノードが取得できるんじゃないでしょうか。
続いて、後者(さらにAPIを使って取得する方法)の場合です。こっちの方が分かりやすいかも。
d.getElementsByTagName(‘タグ名’)とやって、さらにdエレメントの中から検索する方法です。通常、getElementByIdで基点ノードを取得して、そこからあれこれやるほうが効率がいいです。逐一documentから取得していると処理が重くなるし、何より余計なノードが混じりこむことがあるので面倒です。
例えば、
//id=”hogehoge”の要素の中のinput要素を取得する
var e = document.getElementById(‘hogehoge’).getElementsByTagName(‘input’);
という感じで、メソッド連結で取得することが出来ます(この場合、返り値は配列っぽい要素リストです)。
このほうが要素だけを取得できるんでいいかもしれないですね。
但し一点注意が。
var e = document.getElementById(‘hogehoge’).getElementById(‘hogehoge2′);
これは動きません。
取得したエレメント要素にはgetElementByIdのAPIは用意されていませんのでご注意を。素直にgetElementByTagNameとかを使いましょう。
長々と書きましたが、参考にしていただければ幸いです。