質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

動的に追加した要素にaddEventListnerを設定する方法

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 6,501

SugiuraY

score 236

いつもお世話になっております。

動的に追加した要素にaddEventListnerを設定する方法がわからないのです。
調べてもJqueryでの方法は多く出てくるのですが、生のJavascriptでは出てこないので質問させていただきました。

試しにコードを作成してみたのですが、動的に生成された要素elm_2が存在しないためaddEventListner propertyがNullですと返ってくるのかと推察しました。

jqueryの$(document).on('click','hoge',function)のように動的に生成された要素にイベントを設定したいということになります。
よろしくお願いいたします。

<body>

<button id="btn_1">btn</button>

      <script type="text/javascript">
      function adding() {
      var elm_add = document.createElement('button');
      elm_add.id = "hoge";
      elm_add.textContent='btn added';
      var objBody = document.getElementsByTagName("body").item(0);
      objBody.appendChild(elm_add);
      }
      var elm = document.getElementById("btn_1");
      elm.addEventListener("click", adding, false);

      </script>

      <script type="text/javascript">

      function warnings (){
        alert('it works! congraturations!!')
      }


      var elm_2 = document.getElementById("hoge");
      elm_2.addEventListener("click", warnings, false);
     //Uncaught TypeError: Cannot read property 'addEventListener' of null
      </script>
</body>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

以下のように行ってみてはいかがでしょうか?

<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>タイトル</title>
</head>
<body>
<button id="btn_1">btn</button>
<script>
    var num = 0;

    function adding() {
        var elm_add = document.createElement('button');
        elm_add.id = "hoge" + num;
        elm_add.textContent = 'btn added';
        var objBody = document.getElementsByTagName("body").item(0);
        objBody.appendChild(elm_add);
        elm_add.addEventListener("click", warnings, false);
        num++;
    }

    var elm = document.getElementById("btn_1");
    elm.addEventListener("click", adding, false);

    function warnings() {
        alert('it works! congraturations!!')
    }
</script>
</body>
</html>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/15 23:28

    ご返信ありがとうございます。とんでもございません。
    恐らくまさにそこが不明点なポイントです。ご提示いただいたコードでfunction adding () 内において1)の生成と2)の設定はOKで
    1) var elm_add = document.createElement('button');で生成してから
    2) elm_add.addEventListener("click", warnings, false);その要素にイベン

    私のコードのように、addingの外で
    elm_2.addEventListener("click", warnings, false);
    としてイベントを登録することはどちらも設定対象の要素が存在しているように見えるので不思議に感じてました。

    こちらこそ、的違いな発想であれば本当に申し訳ございません。

    キャンセル

  • 2017/10/15 23:45

    今回の場合adding関数はid属性に`btn_1`が設定されたボタンがクリックされるまで実行されません。
    質問者さんのコードでは`var elm_2 = document.getElementById("hoge");`が実行される前にボタンがクリックされていない場合id属性にhogeが設定された要素は存在しないことになりますので、その直後にあるイベントの登録処理はエラーとなります。
    回答文のコードの場合は設定対象の要素が存在する状態でイベントの登録を行っているのでエラーにはなりません。

    キャンセル

  • 2017/10/16 00:59

    ご回答ありがとうございます。
    なるほど、イベント(クリック)が起こるタイミングとその時の要素の状況を適切に把握していなければならないのですね。今回で言えば、一度クリックを押して処理の実行が開始されても、その時点はid="hoge"の要素が存在しないということですか。。
    大変よくわかりました!
    改めて深謝を申し上げます。

    キャンセル

+2

もし2つの<script>にコードを分ける必要がないのなら、elm_addを作った時にその場でaddEventListenerすればいいですよ。

    function adding() {
      var elm_add = document.createElement('button');
      elm_add.id = "hoge";
      elm_add.textContent = 'btn added';
      elm_add.addEventListener("click", warnings);  // <--
      var objBody = document.getElementsByTagName("body").item(0);
      objBody.appendChild(elm_add);
    }

    var elm = document.getElementById("btn_1");
    elm.addEventListener("click", adding);

    function warnings() {
      alert('it works! congraturations!!')
    }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/15 23:30

    ご回答ありがとうございます。
    やはり、初めのイベント設定(adding)の中に、新たに追加した要素のイベントを設定すると、追加イベントを認識して動作するのですね。。。不思議です。

    キャンセル

  • 2017/10/15 23:59

    あ、すみません。s8_chuさんの回答と一緒というかそちらのほうがいいですね。失礼しました。

    質問文のコードだと、
    var elm_2 = document.getElementById("hoge");
    elm.addEventListener("click", adding, false);
    がページが読み込まれるタイミングで実行されます。
    しかしまだ#hogeは存在していません。(ボタン#btn_1を押していないので)
    よって elm_2 に null が入ったためにそのエラーが出たんです。

    キャンセル

  • 2017/10/16 01:00

    コメントありがとうございます。
    みなさんのおかげで現状、問題点、解決方法がよくわかりました。
    本当に勉強になりました。
    御礼申し上げます。

    キャンセル

+1

下記例はクラスですが、それ以外でも基本的に考え方は同じです。

【jQueryを使わずjavascriptだけで書き直した際の記法メモ - Qiita】
https://qiita.com/moriyaman/items/3b3f7878f8ecc2b76372

document.addEventListener('click', function (e) {
  if (e.target.className ==='hoge') {
    // function
  } 
});

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/15 23:38

    コメント誠にありがとうございます。
    またわかりづらくて申し訳ございませんが、ご指摘のコードに基づき、記載したコードで動作自体は無事に確認することができました。

    1) なるほど、document.getElementById('hoge')を即時実行した時点ではまだ、その要素が存在しないため、
    Uncaught TypeError: Cannot read property 'addEventListener' of null
    として要素を見つけることができないとうことですね。
    しかしながら、イベントオブジェクトから特定する場合には、ここではmouseeventでclickに基づき、新たにdocumentをloadして動的に生成された#hogeを識別し追加でイベントが設定できるというように理解いたしました。

    2) オブジェクト指向上のクラスではなく.class class=""という属性のクラスのことでしたか。。失礼いたしました。

    お付き合いを頂きましたことに深く御礼を申し上げます。

    キャンセル

  • 2017/10/15 23:45

    「新たにdocumentをloadして」は何を指しているのでしょうか。どのコードについて書かれていますか?
    もし「document.createElement」について書かれているとしたら、「新たにdocumentをloadして」ではなく「新たに要素を作成することで」くらいが妥当かと思います。少なくとも「load」という動作ではないと思います。

    キャンセル

  • 2017/10/16 01:06

    確かにloadは不適切でした。mouceclickのたびにイベントオブジェクトを呼び出してその時の状況を監視できるので、動的に生成された要素も監視できると解釈しました。
    素人のような言い回しで申し訳ございませんが、なぜ一度のクリックでまだ生成されていない要素を拾うことができるのかが初めは不思議でしょうがなかったのですが、他の方のアプローチと異なり、このようにイベントオブジェクトから都度情報を得て、拾うことができるのだととても勉強になりました!
    夜遅くまでありがとうございます。
    teratailにも感謝です♬よろしくお願い申し上げます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る