質問: こんにちは。Bootstrap の modal についての質問です。 よろしくお願いします。 [jquery 1.10.2] [bootstrap 3.0.0] [Windows10 / IE11, Chrome] [Android 7.0] ### 発生している問題 bootstrap の modal を使用する際、 「modalを閉じた後、閉じきる前に素早く 再度modalを表示する」 という操作を行うと、modal が開かなくなってしまう現象が起きています。 (IEの開発者ツールで確認したところ、javascriptエラーは発生していないようです) # 元々、modal の上に modal を出していて、そのせいかと思っていたのですが # サンプルを作ってみたところ そうでなくても発生するようです? ``` TEST show OYA ×Close 親ダイアログ 親です show KO ×Close 子ダイアログ 子です OK ``` ### 試したこと:modal-backdrop を自分で消してみました IEの開発者ツールで DOM Explorer を見てみたところ、以下の事がわかりました。 1. $.modal("show") を呼ぶと、modal直下に が追加付与される。 2. $.modal("hide") を呼ぶと、上記 modal-backdrop は削除される。 3. 今回問題となっている、素早くmodal再表示を呼んだ際は、 モーダルが表示されていない状態で が追加された状態となっていました。 (class="fade in" ではなく class="fade" となっているので、不可視だがbackdropは居る状態?) 上記を見て、 $(".modal").on('hidden.bs.modal', function(){}) にて .modal-backdrop があったら消すようにしてみましたが、現象は変わりませんでした。 ### 確認したこと:イベントの発生順 log を仕込んでイベントの発生順を確認したところ、 通常の modal 表示時は show → shown, 通常の modal CLOSE時は hide → hidden という順にイベントが発生していますが、問題のケースでは以下のようになっていました。 show → hide → hidden. (shown は無し) 以降 modal 表示ボタンを押しても、show は発生しますが shown まで行きません。 今回の現象はこのイベント発生順によるものだとは思うのですが... そもそも、ダイアログが閉じきるまでは 親要素を触れなくすることはできないのでしょうか。 (hide ではなく hidden で触れるようにしたい?) 何か既出の解決方法等があるのではないかと思い質問させていただきました。 それとも bootstrap を自分で修正しないと駄目でしょうか... 以上です。よろしくお願いします。
回答: bootstrap の modal は二重起動に対して前向きな対応をしていないようですね。 質問者さんが「確認したこと」でおっしゃるとおりイベントが 順序悪く混じってしまうことが問題なのでそれを回避してあげることで解決できるようです。 以下のコードに示すように2種類の状態フラグを管理します。 * `$(this).data('shown')` -> 表示描画処理の完了フラグ * `$(this).data('hidden')` -> 非表示描画処理の完了フラグ 表示/非表示の開始イベント時にそのフラグを判定し完了状態になっていなければ、 順序悪いイベント自体をキャンセルすることで正常な順番で処理をするように強制してあげます。 ``` $("#KoDialog").on('hide.bs.modal', function () { if ($(this).data('shown') === false) return false if (window.console) console.log("* hide.bs.modal"); return true; }); $("#KoDialog").on('hidden.bs.modal', function () { $(this).data('shown', false) $(this).data('hidden', true) if (window.console) console.log("* hidden.bs.modal"); return true; }); $("#KoDialog").on('show.bs.modal', function () { if ($(this).data('hidden') === false) return false; if (window.console) console.log("* show.bs.modal"); return true; }); $("#KoDialog").on('shown.bs.modal', function () { $(this).data('shown', true) $(this).data('hidden', false) if (window.console) console.log("* shown.bs.modal"); return true; }); ```