clickイベントが効かない[JavaScript]

JavaScript&php

これまで遭遇したclickイベントが効かない時のパターンと対処法を備忘も兼ねて記載します。

パターン1:動的に追加した要素のクリックイベントが効かない

一番良くあるパターンですね。例えば下記のようなコードの場合、追加したボタンを押してもボタンは増えないと思います。

See the Pen Untitled by kitaharas (@kitaharas) on CodePen.

なぜなら、$(document).readyでページ読み込み時のみcreateButtonというクラスの要素にイベントを付与していますので、後から増えたボタンには特に付与されません。

解決策:第二引数にクラス名を指定してbodyにイベントを付与する。

See the Pen Untitled by kitaharas (@kitaharas) on CodePen.

これなら動的に増えた要素でも対応可能です。

ちなみに親要素を指定できれば”doby”やその他の要素でもなんでも大丈夫です。
これでだいたいは解消できます。

パターン2:非同期で増えた要素のクリックイベントが効かない

解決策:非同期処理後にイベントを付与する。

例えばJSONを非同期で取得してHTMLとして出力する時とかですね。
非同期処理が終わった後にクリックイベントを付与します。パターン1でもいいかと思いますがたまに使います。

<button id="loadButton">JSONからボタンを生成する</button>
<div id="buttonContainer"></div>

<script>
  document.getElementById("loadButton").addEventListener("click", function() {
    // JSONデータの取得
    async function fetchJSON() {
      try {
        const response = await fetch("example.json");
        const data = await response.json();
        // 取得したJSONデータからボタンを生成
        data.buttons.forEach(function(buttonText) {
          let button = document.createElement("button");
          button.textContent = buttonText;
          button.addEventListener('click',()=>{
            alert('押されました。');
          });
          document.getElementById("buttonContainer").appendChild(button);
        });
      } catch (error) {
         console.error('エラー:', error);
      }
    }
    fetchJSON();
  });
  </script>

JSON取得後この部分でイベントを仕込んでいます。

button.addEventListener('click',()=>{
  alert('押されました。');
});

JSONの中身はこんな感じ

{
  "buttons": ["ボタン1", "ボタン2", "ボタン3"]
}

async/awaitで書きましたがPromise/thenでも非同期の記述はなんでも問題ありません。大事なのは終わった後に処理をする。ということ。

ページ読み込み時に既に存在しているものと非同期で出力したもの全部に同じイベントを入れたい場合は、読み込み時と非同期処理後両方でイベントを付与することになるかと思います。
その時は、クラスを足すなど工夫してイベントが重複しないように注意しましょう。

パターン3:非同期で増えた要素のクリックイベントが効かない②

解決策:setTimeoutで処理の後にイベントを付与する。

既に非同期の処理が入り乱れていていい感じにイベント付与の記述が書けない時など、環境&案件によりいろいろ事情があると思います。

そんな時はsetTimeoutも強い味方です。

例えばイベントを付与する関数があったとして

// イベントを付与する関数
function addEventBtn(btn){
  btn.addEventListener('click',()=>{
   alert('押されました。');
  });
}

setTimeoutで呼び出します。

setTimeout(addEventBtn(btn),0);

0ミリ秒だけどいいの?と思うかもしれませんが実はsetTimeoutはコールバック関数(非同期)としてキュー(タスクの実行)を後回しにしてくれる性質を持っています。

なので0ミリ秒の指定でも今の処理の後で実行してくれます。

状況に応じて使うといいと思います。

パターン4:イベントが重複している。

解決策:off()でイベントを付与する前に一度消す。

ページ読み込み時にイベント付与の関数を呼び出し、その後画面のリサイズでまた呼び出す。など誤ってイベント付与を複数回行ってしまうパターンですね。

一番は複数回行わないことが好ましいですが、状況によってはoff()で消してから付与することも有りです。

// イベントを削除する
function removeClickEvent() {
  $('#elementId').off('click', clickHandler);
}

// クリックイベントを追加する
function addClickEvent() {
  $('#elementId').on('click', clickHandler);
}

// クリックイベントハンドラ
function yourClickHandler(event) {
  // クリックイベントの処理
}

パターン5:onClick=”disabled = true”が設定されている。

これはかなり特殊なパターンですが、送信ボタンなどの二重クリックを防止するために使用されることがあり、フォームのライブラリではデフォルトで記述されていることがあります。

解決策:考え直す

違う方法で二重クリック防止処理を入れましょう。もしくは、

解決策:onClick=”disabled = true”を消してからクリックイベントを付与する。

ですかね。ライブラリの関係で記述の変更ができない場合は上から消す処理を被せるしかありません。

以上になります。

ほとんどの場合はパターン1で対処できるかと思いますが状況によって使い分けると良いかと思います。

コメント

タイトルとURLをコピーしました