木曜日, 7月 05, 2018

jQueryでon()によるイベント定義が入れ子のときの注意点

例えば

$('#foo').on('click', function() {
  $('#bar').hide();

  $.ajax({
    url : url,
    type : "POST",
    beforeSend : function(xhr) {
      xhr.setRequestHeader("If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT");
    },
    dataType : "text",
    data : {
      "user_id" : userId
    }
  }).done(function(data, textStatus, jqXHR) {
    if (data === 'OK') {
      $('#bar').on('click', function() {
        alert('hoge');
      }).show();
    }
    else {
      // 何らかの処理
    }
  }).fail(function(jqXHR, textStatus, errorThrown) {
    // 何らかの処理
  }).always(function() {
    // 何らかの処理
  });
});

の場合、$('#foo')をクリックする度$('#bar')にクリックイベントが追加される。
つまり、

 $('#foo')をクリック -> Ajax成功 -> $('#bar')をクリック:アラートhoge

の後、もう1度同じ操作を繰り返すと

 $('#foo')をクリック -> Ajax成功 -> $('#bar')をクリック:アラートhogeが2回

となる。
よって、つぎのように書くべき。

$('#foo').on('click', function() {
  $('#bar').hide();
  $('#bar').off('click');

  $.ajax({
    url : url,
    type : "POST",
    beforeSend : function(xhr) {
      xhr.setRequestHeader("If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT");
    },
    dataType : "text",
    data : {
      "user_id" : userId
    }
  }).done(function(data, textStatus, jqXHR) {
    if (data === 'OK') {
      $('#bar').on('click', function() {
        alert('hoge');
      }).show();
    }
    else {
      // 何らかの処理
    }
  }).fail(function(jqXHR, textStatus, errorThrown) {
    // 何らかの処理
  }).always(function() {
    // 何らかの処理
  });
});

以上。