2つのリストボックス内でアイテムを入れ替えるBootstrapプラグイン「Bootstrap Dual Listbox」
概要
2つのリストボックス内でアイテムを入れ替えるBootstrapプラグイン「Bootstrap Dual Listbox」を使用したのでメモ。 このUIを言葉で説明するのは難しいので下記のサンプルを参照。 ちなみに、社内アプリケーション作成中に要件として必要だったので導入。
サンプル
Bootstrap Dual Listbox Sample on jsbin.com
コード
↑のサンプルに記載していますが、消えたとき用にコピペ。
- multipleなselect要素に対して
bootstrapDualListbox()
メソッドを呼べばOK。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Bootstrap Dual Listbox Sample</title> <script src="https://code.jquery.com/jquery.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" /> <link href="https://rawgit.com/istvan-ujjmeszaros/bootstrap-duallistbox/master/dist/bootstrap-duallistbox.css" rel="stylesheet" type="text/css" /> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> <script src="https://code.jquery.com/jquery-git.js"></script> <script src="https://rawgit.com/istvan-ujjmeszaros/bootstrap-duallistbox/master/dist/jquery.bootstrap-duallistbox.js"></script> </head> <body class="container"> <select multiple="multiple" size="10" id="sample"> <option value="option1">Option 1</option> <option value="option2">Option 2</option> <option value="option3" selected="selected">Option 3</option> <option value="option4">Option 4</option> <option value="option5">Option 5</option> <option value="option6" selected="selected">Option 6</option> <option value="option7">Option 7</option> <option value="option8">Option 8</option> <option value="option9">Option 9</option> <option value="option0">Option 10</option> </select> </body> </html>
var demo1 = $('#sample').bootstrapDualListbox({ filterTextClear:'全件表示', filterPlaceHolder:'検索', moveSelectedLabel:'選択済みに移動', moveAllLabel:'選択済みに全て移動', removeSelectedLabel:'選択を解除', removeAllLabel:'選択を全て解除', moveOnSelect: false, nonSelectedListLabel: '一覧', selectedListLabel: '選択済み一覧', infoText:'{0}件', showFilterInputs:true, infoTextEmpty:'0件', infoTextFiltered:'{1}件中{0}件表示', });
オプション
V3.0.4(2015/08/07時点の最新)のオプションを日本語訳してみた。(原文は公式のSettings) 英語は得意ではないので参考程度にどうぞ。
オプション名 | 概要 |
---|---|
bootstrap2Compatible | Bootstrap2の場合は「true」?デフォルト「false」 |
filterTextClear | フィルタリングを行っている際に、全件表示するボタンのラベル名。デフォルト「show all」 |
filterPlaceHolder | フィルタリング文字列を入力するテキストボックスのPlaceHolder。デフォルト「Filter」 |
moveSelectedLabel | 選択済みに移動する「→」ボタンにマウスを当てた際に表示される文字列。デフォルト「Move selected」 |
moveAllLabel | 選択済みに全件移動する「→→」ボタンにマウスを当てた際に表示される文字列。デフォルト「Move all」 |
removeSelectedLabel | 選択済みから移動する「←」ボタンにマウスを当てた際に表示される文字列。デフォルト「Remove selected」 |
removeAllLabel | 選択済みから全件移動する「←←」ボタンにマウスを当てた際に表示される文字列。デフォルト「Remove all」 |
moveOnSelect | マウスクリックで移動させるか否か。falseにすると移動させるための「→」、「←」ボタンが表示されます。trueじゃないとAndroidで動かない?デフォルト「true」 |
preserveSelectionOnMove | 移動させた要素を移動後に選択状態にするかどうか。「moveOnSelect」がfalseの場合に効果が出る。デフォルト「false」 |
selectedListLabel | 選択済みの上部に表示される項目名。デフォルトは表示しない。 |
nonSelectedListLabel | 未選択の上部に表示される項目名。デフォルトは表示しない。 |
helperSelectNamePostfix | デフォルトは「helper」。意味わからず。原文「'helper': The added selects will have the same name as the original one, concatenated with this string and 1 (for the non selected list, e.g. element_helper1) or 2 (for the selected list, e.g. element_helper2).」 |
selectorMinimalHeight | 最小の高さ。単位はpxか?デフォルト「100」 |
showFilterInputs | フィルタリングを行うテキストボックスの表示有無。デフォルト「true」 |
nonSelectedFilter | 未選択のフィルタリングテキストボックスの初期値。デフォルト「」 |
selectedFilter | 選択済みのフィルタリングテキストボックスの初期値。デフォルト「」 |
infoText | 現在の件数の文字列。「{0}」が現在の件数に置き換わる。デフォルト「Showing all {0}」 |
infoTextFiltered | フィルタリングされている際の表示文字列。「{0}」がフィルタリング後の件数、「{1}」が全体件数に置き換わる。デフォルト「Filtered {0} from {1}」 |
infoTextEmpty | 要素が0件の際に表示される文字列。デフォルト「Empty list」 |
filterOnValues | Option要素のvalue値でフィルタリングするか否か。デフォルト「false」 |
ちなみに
同じ様なUIがBootsnippもあったけど、少しピンとこなかったので今回はスルーしました。
参考URL
console.logの出力にスタイルを指定する方法
概要
cookpadを見ていてふと開発者ツールを開いたら、警告が表示された。
細かいところまで行き届いてるのか、はたまた、実際にコンソールで操作させて何か行わせた事例でもあったのか。
それとも、小粋な遊び心?(「cookpad.joinUs();
」と実行するとcookpad内の採用情報ページに飛ばされる。)
それはそれとして、表示されたメッセージに色がついていたことに驚愕。 ライブラリでも使っているのかなと思って調べたら、引数でスタイルを渡し、出力文字列に「%c」で指定することでスタイルをあてる事ができるらしい。
具体的には以下の通り。
console.log("%cこれは赤字です。", "color: red");
複数指定する場合には、引数にスタイルを再度追加して、出力文字列には「%c」を再度指定する事で可能。(文字列は「"」で区切られる。)
console.log("%c赤色%c1.5倍", "color: red", "font-size:150%");
指定したスタイルを消すには空文字を指定というのを見ましたが、2015/07/28現在ではこれはChromeのみ。 firefoxだとその前の指定を引き継ぎ、IEだとそもそもスタイルの指定が効きません。
うまく使えば色々便利そうですが、consoleオブジェクトって仕様決まってるんですかね?
参考URL
- cookpad
- Chromeでconsole.logにスタイルを適用する
- console.logにCSSを適用させてみよう
- 2014年時点での効果のあるスタイルの一覧がありました。
リーダブルコード1章から3章までまとめ
概要
社内でリーダブルコードの輪読会を開催してみるので、1章から3章までをまとめた。 せっかくなのでblogにも記載。
はじめに
- 本書の目的は、読みやすいコードを書く事。
- 本書の目的は、君のコードを良くすること。
- コードは理解しやすくなければいけない。
- 誰かが君のコードを読んで理解する時間を最短にする。
1章 理解しやすいコード
1.1 「優れた」コードって何?
1.2 読みやすさの基本定理
- 優れたコードとは読みやすいコード。
- コードは他の人が最短時間で理解できるように書かなければならない。
- ○日後の自分自身も含む
1.3 小さなことは絶対いいこと?
- 大きいより小さい方が理解するまでに係る時間は短い。
- ただしコードが小さければ必ず良いということではない。
- コードは短くしたほうが良いが、「理解するまでにかかる時間」を短くするほうが大切。
1.4 「理解するまでにかかる時間」は競合する?
- 高度に最適化されたコードでも、もっと理解しやすくはできる。
- 理解しやすいコードは設計、テストを行いやすい傾向がある。
でもやるんだよ
- 理解しやすいかどうかを考えるのは大変だが、優秀なプログラマになるために頑張ろう。
2章 名前に情報を詰め込む
2.1 明確な単語を選ぶ
- 「get*」では何をどこからどのように取ってくるのか不明瞭。
- FetchPage,DownloadPageなどはどうか。
- 「size」は何のサイズか不明瞭。
- Height,NumNodes,MemoryBytesなどはどうか。
もっと「カラフル」な単語を探す
2.2 tmpやretvalなどの汎用的な名前を避ける
- 変数の値を表す名前を選ぶ。
- 私はやりがちなので気をつける。
- 汎用的な名前を使用するときには、それ相応の理由がある場合。
tmp
- 生存期間が短くて、一時的な補完が最も適切な変数に使用する。
- temporaryとしての本来の意味がある場合に使用する。
ループイテレータ
- 明確な名前を使用する。(club_i、ci、members_i、miなど)
- club_iならまだわかるが、ciとなると分かりにくい気がする。
- forがネストしてi,jを間違えるというのはよくあるが、名前を付けるほどか?
- そもそも最近はstreamなどループを使用しないようにするのか?
2.3 抽象的な名前よりも具体的な名前を使う
- 正直この辺りは英語が苦手なので難しい。
DISALLOW_EVIL_CONSTRUCTORS
- 正直よくわからず。
--run_locally
- この場合、使用用途ではなく、機能をOptionにするべきという理解しかできなかった。
2.4 名前に情報を追加する
値の単位
- 有効な場合もあると思うが、単位を入れることで助かるケースは少ない気がする。
その他の重要な属性を追加する
- htmlの文字コード : html_utf8
- エスケープ前のコメント : unescaped_comment
- 安易に変数名を付けガチ。ここは意識していきたい。
2.5 名前の長さを決める
スコープが小さければ短い名前でもいい
- 逆に、スコープが大きければ長い名前を付ける。
- 1文字で良いスコープの範囲は数行か?
長い名前を入力するのは問題じゃない
- 補完がある
- が、やはり限界があると思う。(似た長い名前など。)
頭文字と省略形
- 一般的な略語はOK。(str、doc、evalなど)
不要な単語を投げ捨てる
- これによって短くなるのはわかるが、選別が難しい。
2.6 名前のフォーマットで情報を伝える
その他のフォーマット規約
- 大文字やアンダースコアなどに意味を含める。
- Javaではfinalは全て大文字とか。
2.7 まとめ
- 略
3章 誤解されない名前
- 名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する。
3.1 例 : filter()
- フィルタリングの条件でtrueの値かfalseの値か不明瞭。
- 通常はtrueの値ではないか?
3.2 例 : Clip(text, length)
- 正直Clipという単語に馴染みがないのでなんとも言えなかった。
3.3 限界値を含めるときはminとmaxを使う
3.4 範囲を指定するときはfirstとlastを使う
3.5 包含/排他的範囲にはbeginとendを使う
- startといったらendな気がしたが、これは日本人だから?
3.6 ブール値の名前
- is,has,can,shouldを頭に。
- 個人的にcanとshouldはあまり使わない。shouldは見たことないがどうか?
3.7 ユーザの期待に合わせる
例 : get*()
例 : list::size()
- Javaでも以下のコードはあまりよろしくない。
for (int i = 0; i < list.getLength(); i++) {}
3.8 例 : 複数の名前を検討する
- 2章の最初、2.1辺りと被るが、類語辞典などか?
3.9 まとめ
- 最善の名前とは誤解されない名前。
Google Apps Script(GAS)のメモ
久しぶりにGASを触ったらかなり忘れていたのでメモ。
Logger.log("ログ出力");
- ログ出力2(スプレッドシートに出力すると便利)
function log(m) { var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId()); var sheet = ss.getSheetByName("log"); // シートの名前 sheet.appendRow([new Date(), m]); Logger.log(m) }
- コードフォーマット
- Tab
- 値取得
var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId()); var sheet = ss.getSheetByName("シート名"); // シートの名前 var value = sheet.getRange("a1").getValue();
- メール送信
GmailApp.sendEmail("example@example.com", "タイトル", "本文");
- fromとかccとかhtmlmailとか
GmailApp.sendEmail("example@example.com", "タイトル", "本文",{from:"from@example.com",cc:"cc@example.com",htmlBody:"<p>htmlmail</p>" });
- 公式リファレンス
- GASのScriptEditorオレオレチートシート
- 定期実行
リソース → 現在のプロジェクトのトリガー → 表示メッセージ → 適当に設定。- 編集 → 現在のプロジェクトのトリガー
- private関数
- 関数の末尾に「_」を付けると実行関数に表示されなくなる。
エンジニアとしてスカウトされたので色々話しを聞いてみた
概要
3/18にFacebookアドレスにいきなりスカウトメールが届く。内容は以下のような感じ。
ある企業のご依頼による求人に見合う方をお探しする中で、 WEB上の公開情報でyamap様のことを拝見し、ぜひお会いしたいと考え、 スカウトのお声掛けでご連絡をさせて頂きました。
- ↑でyamapとなっている所は本名でした。(Facebookは本名登録してます。) 今は転職する気なんてないですが、何度かメールをやりとりしたら転職に興味なくても、業界の事、転職の事、何でも聞いていいよという事だったので、ネタになるかと思い会ってみる事にしました。
聞きたかったこと
- 何故私に声がかかったのか。
- スカウトがかかるほどの技術者であるとは思えない。
- blogやTwitterからならまだわかるが、何故Facebookから声をかけたのか。
- 私の現在の能力でどの位の給料が貰えるのか。
- 転職市場で求められている技術は何か。
- Groovyは転職市場で評価されているのか。(評価対象になっているのか)
質問と回答
色々あってメモとれなかったので記憶ベースで記載。 括弧内は私の感想です。
- 何故私にメールを?
- blogや勉強会の参加履歴を見るとそれなりに価値があると判断した。(正直ふわっとしてた)
- 私の場合、Facebookからblogなどの情報は辿れないと思うがどうやってみつけたの?
- IDから色々な情報を集め、その一つに以前の勤務先が残っていた。
- それを元にFacebookで検索し、アイコンが同じであるため特定。
- どのような情報からスカウトする相手を探しているのか。
- ブログ、github、勉強会参加歴、slideshare、等々(←の情報は印刷してきてくれた。)
- 一番求められているのは言語は何?
- Android系?
- Androidもあるが、それ以外の方が多い。
- Rubyが人気なイメージあるが?
- 最近はかなり多くなっているが以前Javaが人気。
- JavaとRubyはどの位の差がある?(Javaがまだ一番需要あるとは以外だった)
- JavaScriptはどう?
- クライアントサイドは需要がかなりある。
- サーバ側のJavaScript、node.jsとかはどう?
- あまり聞かない。
- C#は?
- そこそこ。スマホゲームのサーバ側で使用されている印象。(そうなの?)
- Scalaは?
- 求めている企業は増えてきている。
- が、エンジニア自体が少ないのでJavaできればOKというところが多い。
- Groovyは?
- 殆ど聞かないが、1社ある。(ここに突っ込んで聞いてたら、後ほどメールがきて数社の情報くれました。)
- Javaの企業だとJavaのフレームワークとか関連技術とかJavaの周辺技術での要求は?
- 特にない。(ほんとかよ!)
- 高いJavaの技術。
- 高いJavaの技術とは具体的には?
- 特に良いわかりやすい回答はなし。(企業内の面接で判断してるのか?)
- JavaFXは?
- 希望してる企業は聞いたことない。
- COBOLは?
- 担当ではないので詳しくはわからないが、少ないと思う。
- PHPは?
- 最近減ってきていると聞いている。
- 言語以外だとどういうものに需要がある?
- Gitは必須?
- できれば尚良いが、必須ではない。
- 福利厚生とかどう?
- 当然企業ごとそれぞれ違うが、福利厚生があるからそこにするというほどの差はない。
- 残業は?
- 大体はそれなりにある。
- 残業代が100%出るとことかどの位?
- ほとんどない。というかない。みなし残業で35~40hがほとんど。
- ぶっちゃけ年収450なんですが、話に乗ったら上がる?
- 500、550なら可能。(即答された。けど、私の技術なんてわかるわけないので、この程度の年収なら売り方次第では普通に売れるって事なのかな?)
- 1日何人と会ってるの?
- 仕事している人が多いので1日1人会えればいい方。1週間で5人位。
- 会って話して、転職する!って人いる?
- 殆どいないが、それなりにはいる。(やはりこの業界はある程度は常に転職考えているのかな?)
- 会った人から後日連絡とかある?
- 後日連絡があって紹介することは結構多い。
- 紹介される場合どういうフローになるの?
- 面接の前に面談(会社のエンジニアと)をして、お互いに雰囲気掴んだ後に面接というパターンが多い。
- 友人がスカウトの人から会社にいきなり電話が着たという事を言っていたが、そういうことはあるのか。
- スカウト会社によるが、Web上にメールなどの連絡先がどうしても見つからず、所属している会社だけがわかっている状況ならばありえる。
- 電話に出た人にスカウト会社だとわかったら繋いでもらえないのでは?
- 嘘の会社名は言わないが、会社の略称(ABCとかXYZとかアルファベット数文字)で名乗る。
- スカウトして成功したらどの位儲けになるの?
- 転職が決まった方の3ヶ月分の給料を企業から頂く。
- エージェントと変わらない気がするけど儲かるの?
- 依頼された際、調査料的な感じで最初に費用を頂く。
- 依頼は決められた期間に何人紹介するとかノルマあるの?
- 大体はある。(ニッチな技術な場合はない場合もあるらしい)
- 景気いい?
- エンジニアは不足しているので依頼はかなり多い。
- 紹介するエンジニアが足りていない。
- こんな時間まで仕事して、土日もエンジニアと会うとなると、休み少ないような?
- 休みはかなり少ない。大変。(スカウトの人は結構疲れてたw)
(思い出したら随時追加予定)
ぼんやりとしたまとめ
- 特に私が凄いから声がかかったわけではない。(笑)
- エンジニアを探す過程の話を聞いてたら、ある程度Web上にアウトプットしている人は声がかかっていると思われる。
- 向こうは仕事なので結構感じはいい。
- 匿名と思ってWebに公開している情報でも意外と本名と繋がる。(画像検索とかもするらしい)
- 転職する際には転職エージェントに声かけると共に、スカウトの人にも連絡するといいのかも。
- 話はかなり面白かったので暇な人は会ってみると面白いと思う。
- 割りとニッチな技術でも探せば仕事として触れるっぽい。
- AWSは触っといた方がいいっぽい。
- サーバサイドJavaScriptにそれほど食いつきがなかったのは意外。
- 新宿の喫茶店はコーヒーが1000円弱する。(おかわりは300円。ちなみに奢ってくれた)
- スカウト業界は景気いいらしい。
- ↑には書いてないけど、私に紹介しようとした仕事は広告出している会社数社。広告出す所は人不足??
Google Apps ScriptでGoogleスプレッドシートの内容をメールする
概要
会社のメールがGoogle Appsになったので、スプレッドシートやらGoogleドライブと色々連携を試しています。
で、連携をするために使用するのがGoogle Apps Script(略称GAS)ですが、殆どJavaScriptなので超簡単!
とりあえず、スプレッドシートで作った簡易的な進捗管理をメールで送信するようなGASを作成してみました。
実際にはGASは定期的に実行する機能もあるので、毎日朝8~9時に送信するようにしています。
仕様
- 以下の様なスプレッドシートを読み込んで、進捗が完了の列以外をメールする。
No. | やること | 担当 | 進捗 | 期日 | 備考 |
---|---|---|---|---|---|
1 | あれをやる | 田中 | ちょっとだけ | 2015/04/25 | がんばる |
2 | これをやる | 鈴木 | 完了 | 2015/03/25 | すぐやる |
3 | それをやる | 高橋 | 半分くらい | 2015/04/15 | そのうち |
- 送信されるメール
スプレッドシート及びGASのサンプル
※このGASはスプレッドシートに紐付いてないので、動きません。(SpreadsheetApp.getActiveSpreadsheet()
がnull)
コード
var MAIL_ADDRESS = "example@example.com"; function myFunction() { var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId()); var sheet = ss.getSheetByName("進捗一覧"); // シートの名前 // 進捗が100%以外のタスクのIndexを取得 var index = getHeadIndex(sheet, "進捗"); var range = sheet.getRange("a1"); var items = []; for(i=0;i<sheet.getLastRow();i++) { if(range.offset(i, index).getValue() != "完了") { items.push(i); } } var style = " style='border:1px #000000 solid;border-collapse:collapse;'"; var tableList = []; tableList.push("<p>タスク一覧</p>"); //データを取得し、HTMLのテーブルを作成。 tableList.push("<table" + style + ">"); for(i=0;i<items.length;i++) { // iは行のIndex var study = []; for(j=0;j<sheet.getLastColumn();j++) { // jは列のIndex var value = range.offset(items[i], j).getValue(); if(Object.prototype.toString.call(value) == "[object Date]") { value = formatDate(value); } else { value = value.toString().replace("\n", "<br/>"); } study.push(value); } tableList.push("<tr" + style + "><td" + style + ">" + study.join("</td><td" + style + ">") + "</td></tr>"); } tableList.push("</table>"); GmailApp.sendEmail(MAIL_ADDRESS, "進捗連絡", "body", {htmlBody : tableList.join("\n")}); } /** * 指定された名前のHeadを検索し、Indexを返す */ var getHeadIndex = function(sheet, name) { var range = sheet.getRange("a1"); for(i=0;i<sheet.getLastColumn();i++) { if(range.offset(0, i).getValue() == name) { return i; } } }; // DateをYYYY/MM/DD形式に変換する var formatDate = function(date) { var format = 'YYYY/MM/DD'; format = format.replace(/YYYY/g, date.getFullYear()); format = format.replace(/MM/g, ('0' + (date.getMonth() +1)).slice(-2)); format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2)); return format; };
まとめ
上のコードはテーブルで表示させているのでやたら長くなっていますが、データ取得するだけ、メール送るだけなら簡単!
Gmailメインの人はプライベートでも色々使っていけるのかも。
参考
- Google Apps Script入門(ドットインストール)
- とりあえずこれやっとけばOK
- 公式リファレンス
- 英語ですがかなり充実。
- GASのScriptEditorオレオレチートシート
- 「Ctrl + r」で実行と、「Ctrl + Enter」でログ表示。その他色々。
追記(2016/12/22)
単純にメールすればどうすれば良いの?っとコメントいただいたのでシンプルなものを追記します。
各メソッドなどは公式リファレンスを参照してください。
仕様
- 以下の様なスプレッドシートを読み込んで、単純にテキストでメールする。
スプレッドシート
No. | やること | 担当 |
---|---|---|
1 | あれをやる | 田中 |
2 | これをやる | 鈴木 |
3 | それをやる | 高橋 |
送信されるメール
コード
var MAIL_ADDRESS = "example@example.com"; function myFunction() { var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId()); var sheet = ss.getSheetByName("進捗"); // シートの名前 var lastRowIndex = sheet.getLastRow(); var range = sheet.getRange(2, 1, lastRowIndex - 1, 3); var values = range.getValues(); var bodyList = values.map(function(value, index) { return ("No : " + value[0] + "\nやること : " + value[1] + "\n担当 : " + value[2]); }); GmailApp.sendEmail(MAIL_ADDRESS, "進捗連絡", bodyList.join("\n")); }
bootstrap2.3.2においてaタグを使用したボタンで、Clickイベントでdisabledを設定するとhrefの設定が動作しない。
QA@ITに投稿したのですが、一応blogにも記載。
概要
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の設定が動作しない。
サンプル
IEでhttp://jsbin.com/duxiki/1/を開いてボタンをクリックすると、IE9以上では「click」、「href」というアラートがそれぞれ1回ずつ表示されますが、IE8(ドキュメントモードで8にしても再現可能。)では「click」のアラートしか表示されません。 -
コード
↑のコードと同じです。IE9以上では「click」、「href」というアラートがそれぞれ1回ずつ表示されますが、IE8(ドキュメントモードで8にしても再現可能。)では「click」のアラートしか表示されません。
html
<!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>
$("#atag").on("click",function(){ alert("click"); $(this).attr('disabled', true); });
解決方法
問題点
- aタグにdisabled属性は存在しないため、bootstrapがそれっぽく動作するようにしてくれているが、IE8の場合は対応しきれていないというのが問題か?
- bootstrapの挙動からみる予想としては。。。bootstrap内でaタグのボタンのクリックイベントで、クリックイベント発生時にdisabledが設定されている場合、return falseを返す的な処理がclickイベントで行われているのでしょうが、 IE8についてはボタンクリック時ではなく、その時点でのdisabled属性を見てしまっているのではないか。(コードは見ていません。。。)
対処方法
- disabled属性を付与するのではなくあくまでもaタグとして、2重処理を防ぐ。
- つまり、Clickイベント内で2度目の処理だった場合にはfalseを返せばOK。
サンプル
コード
- html
<!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>
$("#atag").on("click",function(){ if(!$(this).hasClass('disabled')) { alert("click"); $(this).addClass("disabled"); } else { return false; } });
まとめ
- bootstrapを使うとaタグもいい感じにボタンっぽくしてくれるけど、あくまでもaはaとして扱う必要がある。
- bootstrapも万能ではない。
- 細かく分析して問題点を把握する。(最初はjQueryも疑っていた)
- IE8はクソ。(サポートが切れるのは2016/1/12。)