1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【JavaScript】内側にinput要素をもつlabel要素のclickイベントが複数回発火してしまう現象とその対策

Posted at

こんにちは。

業務内でlabelタグの内側にinputタグが含まれているような要素にクリックイベントを設定しようとした際、クリックイベントが意図しない回数発火していることに起因する問題が発生しました。

問題が起きた事象とその解決策について、備忘録の意味も込めて記載します。

実装コードと発生した問題

下記CodepenのようなHTML構造の、チェックボックスとテキストが一体化した要素を作成しました。

当該labelタグにclickイベントを設定したところ、本来1回のみ発火してほしいclickイベントが2回発火してしまうという問題が発生しました。

(発生した現象のログは下記CodePenから見ることができます)

See the Pen Untitled by n4gi-dev (@N4gi-dev) on CodePen.

複数回発火する現象の原因

大まかな概要としてはclickイベントを設定しているlabel要素とinput要素の間でバブリングが発生し、クリックイベントが二重登録されていることが原因でした。

より詳細な理由としてはこれらの記事も参考になりました。

対処法

今回のケースでは解決しない例

labelタグの内側がButtonタグのようなケースではe.preventDefault();を先に記載することで解決するケースもあります。

const checkLabel = document.querySelector(".label-area");

checkLabel.addEventListener("click", (e)=>{
  e.preventDefault();
  console.log("clicked");
})

ですが今回のように内側がinputタグの場合、e.preventDefault();だと本来動作してほしいcheckboxの挙動も防ぐことになってしまいます。

See the Pen preventDefault_input by n4gi-dev (@N4gi-dev) on CodePen.

対処法

今回のようなケースではclickイベントではなくchangeイベントをイベントリスナに登録することで解消できました。

イベントリスナを変更することでconsole上で発火する回数を1回に抑えられています。

See the Pen Untitled by n4gi-dev (@N4gi-dev) on CodePen.

changeイベントはinput要素、select要素、textarea要素においてユーザーが要素の値を変更した際に発火するイベントのため、label要素自体ではイベントが発生しません。

label要素に登録したイベントの子要素であるinputタグで発生する1回のみが親要素に伝播されるため、発火回数を1回に抑えられていると考えられます。

最後に

label要素の内側にinput要素が入っているタイプのHTMLを改修するケースは、一からHTMLを構築するよりは元々システムで組み込まれているケースの方が多いと思います。

似た場面で詰まっている人の助けになれば幸いです。

参考記事

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?