QA@IT

bootstrap2.3.2においてaタグを使用したボタンで、Clickイベントでdisabledを設定するとhrefの設定が動作しない。

8659 PV

概要

bootstrap2.3.2においてaタグを使用したボタンで、Clickイベントでdisabledを設定するとhrefの設定が動作しません。
言葉で説明すると複雑なので再現手順及びコードを記載しました。

  • bootstrap2.3.2を使用し、aタグのボタンを作成。
  • aタグのhrefに何らかの処理を設定。
  • jQueryでaタグのClickイベントでaタグをdisabledにする。(2重押下対策が目的)
  • ボタンをクリックする。
    • 通常はClickイベントが動作し、ボタンがdisabledになり、hrefの設定が動作する。
    • IE8の環境ではClickイベント後、ボタンがdisabledになった後、hrefの設定が動作しない。

上記の場合、IE8の場合もボタンをdisabledにし、その後hrefに設定した挙動が行われるためにはどのようにすればよいでしょうか。
質問最下部に記載致しましたが、IE8を判別して強制的に飛ばすという手段は考えつきましたが、スマートな手段がありましたら教えてください。

サンプル

コード

  • 下記のコードでボタンをクリックするとIE8以外ではon、Clickと出力されますが、IE8ではClickが出力されません。
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" type="text/css" />
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <a id="atag" class="btn" href="javascript:method()">CLICK ME</a>
  </body>
</html>

function method() {
  alert("click");
}

$("#atag").on("click",function() {
  alert("on");
  $(this).attr('disabled', true);
});

IE8で分岐して強制的に動作させる手順。

  • 分岐すれば動作はしましたがもう少しスマートな方法はありますでしょうか。
function method() {
  alert("click");
}

$("#atag").on("click",function() {
  alert("on");
  // IE8の場合hrefの設定が動作しないので、強制的に動作させる。
  var userAgent = window.navigator.userAgent.toLowerCase();
  var appVersion = window.navigator.appVersion.toLowerCase();
  if (userAgent.indexOf('msie') != -1 && appVersion.indexOf("msie 8.") != -1) {
      location.href = $(this).attr("href");
  }

  $(this).attr('disabled', true);
});

回答

自己解決しました。
実際の問題とタイトルが異なっているため、後で質問のタイトルも変更致します。

本現象の問題点

  • bootstrap2.3.2においてaタグを使用したボタンで、Clickイベントでdisabledを設定するとhrefの設定が動作しない。
  • aタグにdisabled属性は存在しないため、bootstrapがそれっぽく動作するようにしてくれているが、IE8の場合は対応しきれていないというのが問題と思われます。

問題詳細の予想

bootstrap内でaタグのボタンのクリックイベントで、クリックイベント発生時にdisabledが設定されている場合、return falseを返す的な処理がclickイベントで行われているのでしょうが、
IE8についてはボタンクリック時ではなく、その時点でのdisabled属性を見てしまっているのではないか。

対処方法

  • disabled属性を付与するのではなくあくまでもaタグとして、2重押下を防ぐことで対応が可能です。

サンプル

jsbinというサイトで下記のコードを使用してサンプルを作成しました。
http://jsbin.com/vopoyujahu/2

修正コード

<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" type="text/css" />
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <a id="atag" class="btn" href="javascript:alert('href')">CLICK ME</a>
  </body>
</html>
document.getElementById("atag").onclick=function() {
  if(!$(this).hasClass('disabled')) {
    alert("click");
    $(this).addClass("disabled");
  } else {
    return false;
  }
};

編集 履歴 (2)
  • すでに気づいているかもしれませんが、二度押し防止で言えば別のブラウザでもイベントは発火していますよ。(私の回答に追記したdivタグで囲う場合、その挙動も同じになります(=disableでも何度でも押せます)。) -
  • ありがとうございます。確かにその通りですね。二度押し防止というのも誤りでした。画面遷移(hrefの設定)が二回以上発生しない事が要件ですね。 -

methodの方で要素を無効化するのではどうでしょう。

一つにはmethod内で実行してほしいメソッド内容を書き換える。

var nextMethod = undefined;
function method() {
  alert("click");
  if(nextMethod !== undefined){
    nextMethod();
    nextMethod = undefined;
  }
}

$("#atag").on("click",function() {
  var $el = $(this);
  nextMethod = function(){ $el.attr('disabled', true); };
});

または、methodにセレクタを渡してしまう

function method(selectorToDisable) {
  alert("click");
  $(selectorToDisable).attr('disabled', true);
}
<!-- html 側でセレクタを指定する必要がある -->
<a id="atag" class="btn" href="javascript:method('#atag')">CLICK ME</a>

※ IE8だとconsole無いのでalertにしてあります。

最初の例の場合はnextMethodを同時に複数で書き換えた場合に片方しか発火しなかったり、順序性が保証されているかを気にしなければなりません。
後の例では実行タイミングが変わるので気をつけないといけないかもしれません。


methodを常に呼ぶならclickイベントでmethodを呼ぶ手もあるかもしれません。

var nextMethod = undefined;
function method($el) {
  alert("click");
  $el && $el.attr('disabled', true);
}

$("#atag").on("click",function() {
  method($(this));
});

作ろうとしているアプリの動作の都合もあるでしょうから、採用できるかはわかりませんが参考までに。


追記。

タグの方が自由に追加できるのなら、aタグの外にdivを作って親を無効化してしまうとIE8で同じ様な動作にはなりました。
しかしChromeではだめだったので、ie8判定は必要になってしまいますね。

  <div>
  <a id="atag" class="btn" href="javascript:method()">CLICK ME</a>
  </div>
function method() {
  alert("click");
}

$("#atag").on("click",function() {
  $(this).parent().attr('disabled', true);
});

あとは IE8の判定自体を簡素化するために、条件付きコメントを使ってしまう手も。
クリックイベントは上記のdivで囲うパターンでやっていますが他の方法にも使えると思います。
他のバージョンでIE8モードやIE8 エミュレートモードやエンタープライズモード(IE8相当だった気がする)だとどうなるかはわかりません。

  <script>var isIE8=false;</script>
  <!--[if IE 8 ]><script>isIE8=true;</script><![endif]-->
$("#atag").on("click",function() {
  if(isIE8){
    alert('IE8');
    $(this).parent().attr('disabled', true);
  }else{
    alert('not IE8');
    $(this).attr('disabled', true);
  }
});

href属性もフレームワークが生成しているのでしょうが、もしそうでなければhref属性に複数メソッド記述する方法もあります。

<a id="atag" class="btn" href="javascript:myMethod();method()">CLICK ME</a>

ぱっと思いついたのはこんなところです。

編集 履歴 (1)
  • 回答ありがとうございます。
    hrefに設定される側の関数を変更するという考えはありませんでした。
    ただ、現在のアプリでは、例として出させて頂いたmethod(hrefに設定される関数)は、
    アプリではフレームワークで動的に作成されるため、手を入れることができません。

    Clickイベントとして設定する関数の方で実現したいと考えております。
    (クリックイベントである必要はありませんが。)
    -
  • 追記して頂きありがとうございます。
    親にdisabledを設定するとはこれまた考えが至りませんでした。また、条件付きコメントは完全に忘れていました。今回は回答頂き本当にありがとうございました。大変勉強になりました。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。