このブログのはてなブックマーク数 このエントリーをはてなブックマークに追加

知らなきゃ絶対損するPCマル秘ワザ

知らなきゃ損するPC情報を分かりやすくメモする個人ブログ。
『月,水,金』の週3回更新!(予定)

このブログ内をキーワードで検索することもできます。
Loading



最新記事
  • iPhone:iCloudを使って新しいiPhoneにデータを移行する (11/20)
  • iPhoneX を1週間使ってみて分かったこと (11/17)
  • ニコニコ動画:動画を見ようとするとログインしろと言われる (11/15)
  • Windows10: Win7 の Aero Glass のような透過効果を使う (11/13)
  • iPhone:1ヶ月前のイベントが「カレンダー」から消えてしまう (11/08)
  • 管理人より
    2300万アクセス突破しました。ありがとうございます。

    jQuery:追加した「ボタン」をクリックしてもイベントが発火しない

    このエントリーをはてなブックマークに追加
    操作画面


    こんにちは、さち です。

    先日、「スクフェス ツールズ」をいじっているときに
    jQuery で要素(入力欄)を動的に追加したんですが
    その追加した要素に設定しているイベントが発火せずハマりました。

    解決方法はそんなに難しくないですが
    知らないとどうしようもない方法なので記事にまとめておきます。




    問題の症状

    jQuery Mobile を利用したこのようなページがあります。
    操作画面

    HTML ソースはこんな感じ。
    <div class="wrap">
    <button class="friends">たーのしー!</button>
    </div>

    <button class="push">追加</button>

    続いて、下記のような jQuery(JavaScript) を作りました。
    .friends を持つボタンをクリックすると内容がダイアログで表示されます。
    「追加」ボタンをクリックすると新しいボタン「わーい!」が追加されます。
    (trigger('create') ってなーに?というヒトはこちらの記事をどうぞ)
    //「.friends」のボタンをクリックしたらダイアログを表示
    $('.friends').click(function() {
    var txt = $(this).text();
    alert(txt);
    });

    //「追加」をクリックすると「わーい!」ボタンを追加
    $('.push').click(function() {
    var $btn = $('<button>').addClass('friends').text('わーい!');
    $('.wrap').append($btn).trigger('create');
    });

    「たーのしー!」をクリックするとこうなります。
    操作画面

    「追加」をクリックして、新しく「わーい!」を追加しました。
    操作画面

    「わーい!」をクリックします。しかし、ダイアログが出ません。
    えー、.friends を持っているボタンなのになんでー?
    操作画面




    解決方法

    ダイアログを表示するコードを
    click() ではなく on() を使って次のように書き換えます。
    //変更前
    $('.friends').click(function() {
    var txt = $(this).text();
    alert(txt);
    });

    //変更後
    $(document).on('click', '.friends', function() {
    var txt= $(this).text();
    alert(txt);
    });

    これで、追加した「わーい!」をクリックしてもダイアログが出ます。
    わーい!すごーい!
    操作画面




    問題の原因(追記)

    原因は、イベントを設置する場所です。

    click() は、実は bind() を簡略化した記述方法です。
    //click()を使ってこう書くのは……
    $('.friends').click(function() {
    var txt= $(this).text();
    alert(txt);
    });

    //bind()を使ってこう書くのとまったく同じ
    $('.friends').bind('click', function() {
    var txt= $(this).text();
    alert(txt);
    });

    bind() は、指定したセレクター(場所)に直接イベントを設置します。
    また、イベントの発火場所も同じセレクター(場所)になります。
    つまり、bind() はイベントの設置場所と発火場所が同じです
    例で言えば、イベントの設置場所と発火場所はともに .friends です。
    $('.friends').bind('click', function() {
    var txt= $(this).text();
    alert(txt);
    });

    //bind()の構造
    $('イベントの設置場所&発火場所').bind('イベント型', function() {
    /* 実行する内容 */
    });

    イベントの設置はページを開いた直後に行われます。
    例で言えば .friend を持つ要素は2つありますが
    bind() によりイベントが設置されるのは最初からある「たーのしー!」の方だけ。
    後で動的に追加する「わーい!」の方には設置されません。
    イメージ

    この状態で「わーい!」の方をクリック(発火)します。
    バブリングという仕組みによりクリックの情報が親(上)の要素に伝わりますが
    経路上にイベントがないため、イベントは発生しません(不発)。
    (「たーのしー!」をクリックした場合、同じ場所にあるイベントが発生します)
    イメージ

    正常に動作する on() を使った記述は下記のとおりでしたよね。
    on() の場合、イベントは先頭で指定したセレクター(場所)に設置されます。
    ただし、イベントの発火場所は on() の第二引数で指定したセレクター(場所)です。
    つまり、on() はイベントの設置場所と発火場所を別々にできます
    例で言えば、イベントの設置場所は document、発火場所は .friends です。
    $(document).on('click', '.friends', function() {
    var txt= $(this).text();
    alert(txt);
    });

    //on()の構造
    $('イベントの設置場所').on('イベント型', 'イベントの発火場所', function() {
    /* 実行する内容 */
    });

    この場合、ページを開いた直後のイベントの設置は document に行われます。
    イメージ

    この状態で「わーい!」をクリック(発火)すると
    バブリングにより親(上)の要素に伝わり document にたどり着き
    そこにあるイベントが発生します。
    「たーのしー!」の方でも同様の理由でイベントが発生します。
    イメージ

    div.wrapbutton.push をクリックしてもイベント発火するんじゃ?』
    と思うかもしれませんが、それはありません。
    on() の第二引数で指定した場所での発火にしか反応しません。
    つまり、例の場合では .friends 以外をクリックしてもイベントは発火しません。

    すでに気づいている人もいるかもしれませんが
    実は、イベントを設置する場所は document である必要はありません。
    例の場合で言えば、div.wrapbody などの親要素でも構いません。
    document が最上位なので面倒なことになりにくいというだけです。
    (厳密には最上位ではないけれど話がややこしくなるから省略)

    ちなみに、live()delegate() でも
    後から追加した要素でイベントを発火できますが
    現在は共に廃止や非推奨になっているので使わない方がいいです。
    特別な理由でもない限り on() を使いましょう。
    //live()をon()で再現
    $('.friends').live('click', function(){});
    $(document).on('click', '.friends', function(){});

    //delegate()をon()で再現
    $(document).delegate('.friends', 'click', function(){});
    $(document).on('click', '.friends', function(){});

    //click(),bind()をon()で再現
    $('.friends').click(function(){});
    $('.friends').bind('click', function(){});
    $('.friends').on('click', function(){});




    仕組みが分かれば今後はきっと大丈夫。
    後から動的に追加したボタン等のイベントは
    click()bind() などではなく $(document).on() を使う!
    しっかり覚えておきたいと思います。



    【関連記事】

       → jQuery Mobile:追加した要素(select等)にスタイルが付かない









    このエントリーをはてなブックマークに追加




    管理人だけが読めるコメントにする(返信はしません)
    【お知らせ】
    • コメントは承認制です。反映に時間がかかります。
    • Yahoo!BBはスパムコメントが多いため一部規制中です。
    • URLを含む投稿はできません。必要な場合は最初のhを削って下さい。
    • 記事に直接関係ない個人のトラブルにはお答えできません。
    • Android は使ったことがないので質問を頂いても答えられません。
    • その他詳細はこちら


    多分
    $('.friends').on('click', function() {
    var txt= $(this).text();
    alert(txt);
    });
    でもいけますよー!!
    名無し | 2017/02/21/Tue [EDIT]
    試してみたんですが、その記述の on() ですと
    実質 bind() と同じ動きになるのでダメみたいです。
    うみの さち | 2017/02/21/Tue [EDIT]



    記事別の週間アクセス数ランキングです。こちらの記事もぜひ読んでみて下さい。

    2008-2017 知らなきゃ絶対損するPCマル秘ワザ  無断転載禁止

    ブログパーツ