jQueryまたはgetElementByIdなどのDOMメソッドが要素を見つけられないのはなぜですか?

505
Felix Kling 2012-12-25 22:26.

document.getElementById$("#id")または他のDOMメソッド/ jQueryセレクターが要素を見つけられない理由として考えられるものは何ですか?

問題の例は次のとおりです。

  • jQueryがイベントハンドラーのバインドに黙って失敗する
  • jQueryの"ゲッター"メソッド(.val().html().text())を返しますundefined
  • nullいくつかのエラーのいずれかが発生する標準のDOMメソッドが返されます。

Uncaught TypeError:nullのプロパティ '...'を設定できませんUncaughtTypeError:nullのプロパティ '...'を読み取れません

最も一般的な形式は次のとおりです。

Uncaught TypeError:nullのプロパティ 'onclick'を設定できません

Uncaught TypeError:nullのプロパティ 'addEventListener'を読み取れません

Uncaught TypeError:nullのプロパティ 'style'を読み取れません

7 answers

506
canon 2012-01-04 08:06.

スクリプトの実行時に、検索しようとした要素がDOMにありませんでした。

DOMに依存するスクリプトの位置は、その動作に大きな影響を与える可能性があります。ブラウザはHTMLドキュメントを上から下に解析します。要素はDOMに追加され、スクリプトは(通常)検出されたときに実行されます。これは、順序が重要であることを意味します。通常、スクリプトは、マークアップの後半に表示される要素を見つけることができません。これらの要素はまだDOMに追加されていないためです。

次のマークアップを検討してください。スクリプト#1は<div>、スクリプト#2が成功している間、検索に失敗します。

<script>
  console.log("script #1: %o", document.getElementById("test")); // null
</script>
<div id="test">test div</div>
<script>
  console.log("script #2: %o", document.getElementById("test")); // <div id="test" ...
</script>

それで、あなたは何をすべきですか?いくつかのオプションがあります。


オプション1:スクリプトを移動する

スクリプトをページのさらに下、body終了タグの直前に移動します。このように編成されているため、スクリプトが実行される前に、ドキュメントの残りの部分が解析されます。

<body>
  <button id="test">click me</button>
  <script>
    document.getElementById("test").addEventListener("click", function() {
      console.log("clicked: %o", this);
    });
  </script>
</body><!-- closing body tag -->

注:スクリプトを下部に配置することは、一般的にベストプラクティスと見なされます。


オプション2:jQueryの ready()

次を使用して、DOMが完全に解析されるまでスクリプトを延期します。$(handler)

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
  $(function() {
    $("#test").click(function() {
      console.log("clicked: %o", this);
    });
  });
</script>
<button id="test">click me</button>

注:単純に結合することができるDOMContentLoadedか が、それぞれがその警告を持っています。jQueryはハイブリッドソリューションを提供します。window.onloadready()


オプション3:イベントの委任

委任されたイベントには、後でドキュメントに追加される子孫要素からのイベントを処理できるという利点があります。

要素がイベントを発生させると(それがバブリングイベントであり、その伝播を停止するものがない場合)、その要素の祖先の各親もイベントを受け取ります。これにより、ハンドラーを既存の要素にアタッチし、イベントが子孫からバブルアップするときにイベントをサンプリングできます...ハンドラーがアタッチされた後に追加されたものも含まれます。イベントをチェックして、目的の要素によって発生したかどうかを確認し、発生した場合はコードを実行するだけです。

jQueryon()はそのロジックを実行してくれます。イベント名、目的の子孫のセレクター、およびイベントハンドラーを提供するだけです。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
  $(document).on("click", "#test", function(e) {
    console.log("clicked: %o",  this);
  });
</script>
<button id="test">click me</button>

注:通常、このパターンは、ロード時に存在しなかった要素、または大量のハンドラーのアタッチを回避するために予約されています。また、document(説明のために)ハンドラーをアタッチしましたが、最も近い信頼できる祖先を選択する必要があることも指摘しておく価値があります。


オプション4:defer属性

defer属性を使用します<script>

[ defer、ブール属性、]は、ドキュメントが解析された後、起動する前にスクリプトが実行されることをブラウザに示すために設定されますDOMContentLoaded

<script src="https://gh-canon.github.io/misc-demos/log-test-click.js" defer></script>
<button id="test">click me</button>

参考までに、その外部スクリプトのコードを次に示します。

document.getElementById("test").addEventListener("click", function(e){
   console.log("clicked: %o", this); 
});

注:defer属性は、確かにそうです魔法の弾丸のようにしかし、それは点に注意することが重要です...
1.defer外部スクリプトのみを使用することができ、すなわち:を有するものsrcの属性を。
2.ブラウザのサポートに注意してください。つまり、IE <10でのバグのある実装

154
Felix Kling 2012-12-25 22:26.

短くて単純:探している要素がドキュメントに(まだ)存在しないためです。


この回答の残りのために私が使用するgetElementById一例として、しかし同様に当てはまりgetElementsByTagNamequerySelector選択要素こと、および任意の他のDOM方法。

考えられる理由

要素が存在しない理由は2つあります。

  1. 渡されたIDを持つ要素は、実際にはドキュメントに存在しません。渡すgetElementByIdIDが(生成された)HTMLの既存の要素のIDと実際に一致していること、およびIDのスペルを間違えていないことを再確認する必要あります(IDでは大文字と小文字が区別されます!)。

    ちなみに、実装とメソッドを備えた現代のブラウザ大部分では、CSSスタイルの表記法を使用して、要素をその下で取得する方法とは対照的に、たとえば次のように要素を取得します。最初の文字は必須であり、2番目の文字は要素が取得されないことにつながります。querySelector()querySelectorAll()iddocument.querySelector('#elementID')iddocument.getElementById('elementID')#

  2. 呼び出した時点では、要素は存在ませんgetElementById

後者の場合は非常に一般的です。ブラウザはHTMLを上から下に解析して処理します。つまり、そのDOM要素がHTMLに表示される前に発生するDOM要素の呼び出しはすべて失敗します。

次の例を考えてみましょう。

<script>
    var element = document.getElementById('my_element');
</script>

<div id="my_element"></div>

div表示さますscript。スクリプトが実行された時点では、要素はまだ存在しておらずgetElementByIdを返しnullます。

jQuery

同じことがjQueryのすべてのセレクターに当てはまります。セレクターのスペル間違えた場合、または実際に存在する前に要素を選択しようとした場合、jQueryは要素を検出しません。

追加のひねりは、プロトコルなしでスクリプトをロードし、ファイルシステムから実行しているためにjQueryが見つからない場合です。

<script src="//somecdn.somewhere.com/jquery.min.js"></script>

この構文は、スクリプトがプロトコルhttps://のページにHTTPS経由でロードできるようにし、プロトコルhttp://のページにHTTPバージョンをロードできるようにするために使用されます。

ロードを試みたり失敗したりするという不幸な副作用があります file://somecdn.somewhere.com...


ソリューション

を呼び出す前にgetElementById(またはそのことについては任意のDOMメソッド)、アクセスする要素が存在すること、つまりDOMがロードされていることを確認してください。

これは、対応するDOM要素のにJavaScriptを配置するだけで確認できます。

<div id="my_element"></div>

<script>
    var element = document.getElementById('my_element');
</script>

この場合、終了bodyタグ(</body>)の直前にコードを配置することもできます(すべてのDOM要素はスクリプトの実行時に使用可能になります)。

他の解決策には、load [MDN]またはDOMContentLoaded [MDN]イベントのリッスンが含まれます。このような場合、JavaScriptコードをドキュメントのどこに配置するかは重要ではありません。すべてのDOM処理コードをイベントハンドラーに配置することを忘れないでください。

例:

window.onload = function() {
    // process DOM elements here
};

// or

// does not work IE 8 and below
document.addEventListener('DOMContentLoaded', function() {
    // process DOM elements here
});

イベント処理とブラウザの違いの詳細については、quirksmode.org記事を参照してください。

jQuery

まず、jQueryが正しくロードされていることを確認します。ブラウザの開発者ツール使用して、jQueryファイルが見つかったかどうかを確認し、見つからなかった場合はURLを修正します(たとえば、最初にhttp:またはhttps:スキームを追加したり、パスを調整したりします)。

load/DOMContentLoaded イベントをリッスンすることは、jQueryが.ready() [docs]で行っていることとまったく同じです。DOM要素に影響を与えるすべてのjQueryコードは、そのイベントハンドラー内にある必要があります。

実際、jQueryチュートリアルは明示的に次のように述べています。

jQueryを使用するときに行うほとんどすべてのことは、ドキュメントオブジェクトモデル(DOM)を読み取ったり操作したりするため、DOMの準備ができたらすぐにイベントなどの追加を開始する必要があります。

これを行うために、ドキュメントの準備完了イベントを登録します。

$(document).ready(function() {
   // do stuff when DOM is ready
});

または、簡略構文を使用することもできます。

$(function() {
    // do stuff when DOM is ready
});

どちらも同等です。

16
George Mulligan 2016-01-06 13:34.

アクセスしようとしている要素が内にiframeあり、コンテキスト外でアクセスしようとするiframeと、失敗する原因にもなります。

iframeで要素を取得したい場合は、ここでその方法を確認できます。

16
sumit 2014-01-08 02:12.

IDベースのセレクターが機能しない理由

  1. IDが指定された要素/ DOMはまだ存在しません。
  2. 要素は存在しますが、DOMに登録されていません[Ajax応答から動的に追加されたHTMLノードの場合]。
  3. 同じIDを持つ要素が複数存在するため、競合が発生しています。

ソリューション

  1. 宣言後に要素にアクセスするか、次のようなものを使用してみてください $(document).ready();

  2. Ajax応答からの要素に.bind()は、jQueryのメソッドを使用します。古いバージョンのjQuery.live()も同じです。

  3. ツール[ブラウザ用のwebdeveloperプラグインなど]を使用して、重複するIDを見つけて削除します。

13
Nathan Bubna 2013-12-07 07:29.

@FelixKlingが指摘したように、最も可能性の高いシナリオは、探しているノードが(まだ)存在しないことです。

ただし、最近の開発手法では、DocumentFragmentsを使用するか、現在の要素を直接デタッチ/再アタッチするだけで、ドキュメントツリーの外部のドキュメント要素を操作できることがよくあります。このような手法は、JavaScriptテンプレートの一部として、または問題の要素が大幅に変更されている間の過度の再描画/リフロー操作を回避するために使用できます。

同様に、最新のブラウザに展開されている新しい「シャドウDOM」機能を使用すると、要素をドキュメントの一部にすることができますが、document.getElementByIdとそのすべての兄弟メソッド(querySelectorなど)でクエリを実行することはできません。これは、機能をカプセル化し、具体的に非表示にするために行われます。

繰り返しになりますが、探している要素が(まだ)ドキュメントに含まれていない可能性が高いため、Felixが示唆しているように行う必要があります。ただし、要素が(一時的または永続的に)見つからない理由は、それだけではないことにも注意する必要があります。

8
CertainPerformance 2019-05-10 23:29.

スクリプトの実行順序が問題ではない場合、問題のもう1つの考えられる原因は、要素が適切に選択されていないことです。

  • getElementById渡された文字列はそのままIDである必要があり、それ以外は必要ありません。渡された文字列の前#に。を付け、IDが。で始まらない場合#、何も選択されません。

      <div id="foo"></div>
    
      // Error, selected element will be null:
      document.getElementById('#foo')
      // Fix:
      document.getElementById('foo')
    
  • 同様に、の場合getElementsByClassName、渡された文字列の前に.:を付けないでください。

      <div class="bar"></div>
    
      // Error, selected element will be undefined:
      document.getElementsByClassName('.bar')[0]
      // Fix:
      document.getElementsByClassName('bar')[0]
    
  • querySelector、querySelectorAll、およびjQueryを使用して、要素を特定のクラス名と照合.するには、クラスの直前に配置します。同様に、特定のIDを持つ要素を照合#するには、IDの直前に置きます。

      <div class="baz"></div>
    
      // Error, selected element will be null:
      document.querySelector('baz')
      $('baz')
      // Fix:
      document.querySelector('.baz')
      $('.baz')
    

    ここでのルールは、ほとんどの場合、CSSセレクターのルールと同じであり、ここで詳細に確認できます

  • 2つ以上の属性(2つのクラス名、またはクラス名とdata-属性など)を持つ要素を照合するには、各属性のセレクター、スペースで区切らずにセレクター文字列に並べます(スペースは子孫セレクタ)。たとえば、次を選択します。

      <div class="foo bar"></div>
    

    クエリ文字列を使用します.foo.bar。選ぶ

      <div class="foo" data-bar="someData"></div>
    

    クエリ文字列を使用します.foo[data-bar="someData"]<span>以下を選択するには:

      <div class="parent">
        <span data-username="bob"></span>
      </div>
    

    を使用しますdiv.parent > span[data-username="bob"]

  • 大文字とスペル、上記のすべてにとって重要です。大文字と小文字が異なる場合、またはスペルが異なる場合、要素は選択されません。

      <div class="result"></div>
    
      // Error, selected element will be null:
      document.querySelector('.results')
      $('.Result')
      // Fix:
      document.querySelector('.result')
      $('.result')
    
  • また、メソッドに適切な大文字とスペルが含まれていることを確認する必要があります。次のいずれかを使用します。

    $(selector)
    document.querySelector
    document.querySelectorAll
    document.getElementsByClassName
    document.getElementsByTagName
    document.getElementById
    

    その他のスペルや大文字の使用は機能しません。たとえば、document.getElementByClassNameはエラーをスローします。

  • これらのセレクターメソッドに文字列を渡すようにしてください。文字列ではないものを、などに渡すとquerySelectorgetElementByIdほぼ確実に機能しません。

  • 選択する要素のHTML属性が引用符で囲まれている場合、それらは単純な一重引用符(一重引用符または二重引用符)である必要があります。ID、クラス、または属性で選択しようとしている場合、中引用符は機能するか、機能しません。

0
Jatinder Kumar 2020-04-18 22:21.

私があなたのコードを試したとき、それはうまくいきました。

イベントが機能していない唯一の理由は、DOMの準備ができておらず、IDが「event-btn」のボタンの準備ができていない可能性があります。そして、JavaScriptが実行され、イベントをその要素にバインドしようとしました。

バインドにDOM要素を使用する前に、その要素の準備ができている必要があります。それを行うには多くのオプションがあります。

オプション1:ドキュメント準備完了イベント内でイベントバインディングコードを移動できます。お気に入り:

document.addEventListener('DOMContentLoaded', (event) => {
  //your code to bind the event
});

オプション2:タイムアウトイベントを使用して、バインディングを数秒間遅らせることができます。お気に入り:

setTimeout(function(){
  //your code to bind the event
}, 500);

オプション3:JavaScriptインクルードをページの下部に移動します。

これがお役に立てば幸いです。

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

今週のコミックコンですべての素晴らしいものに追いつく方法

今週のコミックコンですべての素晴らしいものに追いつく方法

サンディエゴコミックコンは今週開幕し、オタクのアナウンス、ポスター、予告編、お気に入りの番組や映画のからかいでいっぱいになります。SDCCは、コンベンションフロア全体の多くのパネルで行われているため、すべてに対応するのは難しい場合があります。

Googleの9千万ドルの和解はアプリ開発者にとってもGoogleにとっても勝利ですか?

Googleの9千万ドルの和解はアプリ開発者にとってもGoogleにとっても勝利ですか?

小さなアプリ開発者は金曜日に発表された法的な和解でグーグルから9千万ドルをこじ開けた。アップルとの同様の合意に続いて熱くなった。金曜日のブログ投稿で、Googleは、Androidメーカーが市場での優位性を悪用してPlayストア経由でのアプリ内購入に対して30%の料金を不当に請求したと主張するアプリ開発者との訴訟を解決するために、9千万ドルを支払うことに合意したと述べました。

RadioShackのTwitterはハッキングされていませんでした、それはただの暗号のサクラです

RadioShackのTwitterはハッキングされていませんでした、それはただの暗号のサクラです

今週、RadioShackのTwitterアカウントは、奇妙なものから完全にひどいものになりました。短い順序で、会社のフィード全体が、バイブレーター、「ビッグティット」(スペルミス)、有名人やその他の企業アカウントを荒らしているツイートなど、NSFW素材の真の山になりました。

ヒッグス粒子から10年後、物理学にとって次の大きなものは何ですか?

ヒッグス粒子から10年後、物理学にとって次の大きなものは何ですか?

大型ハドロン衝突型加速器のトンネル内にあるコンパクトミュオンソレノイド(CMS)検出器。2012年7月4日、CERNの科学者たちは、1960年代に最初に提案された素粒子であるヒッグス粒子の観測を確認しました。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Un breve viaje espacial sobre conceptualizar el diseño

Complicarse la vida, mezclar churros con meninas (nada de ovejas) y encontrar valor en un trastero que adquiriste en una puja.

Un breve viaje espacial sobre conceptualizar el diseño

Bien. Hay un momento en toda salida al espacio exterior en el que de la tensión, la velocidad y las altas temperaturas derivadas del cruce de estratosfera a ionosfera se pasa a un momento de súbita calma, donde se despliega la vista completa del paisaje espacial que nos rodea.

Seguindo Todos os Protocolos (2022), de Fábio Leal

Seguindo Todos os Protocolos (2022), de Fábio Leal

Chico quer transar. Até aí, tudo bem.

多元宇宙—Junø

多元宇宙—Junø

チェーン間アカウントがJunoに登場します。異なるブロックチェーン間でスマートコントラクトの構成可能性と真の相互運用性を提供します。

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「​​ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。

Language