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

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

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

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

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

オーケーグッド770HPランボルギーニセンテナリオは十分に正気ではない

オーケーグッド770HPランボルギーニセンテナリオは十分に正気ではない

ランボルギーニの創設者であるフェルッチオランボルギーニが100歳になるのは毎日ではありません(そうです、彼は死んでいて、まだ死んでいると思います。

彼らが買った1台の車からAppleの車の計画について私たちが推測できること

彼らが買った1台の車からAppleの車の計画について私たちが推測できること

Appleが自動車分野に参入するという噂はかなり前から渦巻いており、AppleウォッチャーがSixtyEight Researchという会社がAppleの自動車研究開発のシェル会社である可能性が高いと判断したとき、その渦巻きは本当に渦巻いた。また、会社が購入した車は1台だけであることが知られており、その車はAppleが何を考えているかについての手がかりでいっぱいになる可能性があることも伝えています。

天文学者は太陽系の9番目の惑星の新しい証拠を見つけます

天文学者は太陽系の9番目の惑星の新しい証拠を見つけます

太陽系の外側にある架空の大きな物体である惑星Xの探索は、何十年にもわたって人間を魅了してきました。その検索の最新の章は、地球の10倍の大きさで、公転周期が15であるほど遠くにある惑星を指しています。

キャムニュートン、ゴッドダム

キャムニュートン、ゴッドダム

カムニュートンは昨日、簡単な265ヤードと3回のタッチダウンでファルコンズを引き裂き、別の素晴らしいゲームをしました。その日のハイライトは、上のタッチダウンスローでした。これは、視聴するたびにばかげているだけです。

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。

コンセプト ドリフト: AI にとって世界の変化は速すぎる

コンセプト ドリフト: AI にとって世界の変化は速すぎる

私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

犯罪擁護派のオークランドが暴力犯罪者のロミオ・ロレンゾ・パーハムを釈放

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

メリック・ガーランドはアメリカに失敗しましたか?

バイデン大統領の任期の半分以上です。メリック・ガーランドは何を待っていますか?

メリック・ガーランドはアメリカに失敗しましたか?

人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。

Language