js から Bootstrap の Modal を表示してそのモーダル上での操作に応じてなにかしたいとき(典型的には確認ダイアログとか)、Modal を Promise として扱えるようにしておくと async/await で直列に書けて便利です。
const promisifyModal = (modal, param) =>{
const $modal = $(modal);
return new Promise((resolve) => {
$modal
.data('modal-param', param)
.data('modal-result', null)
.off('hidden.bs.modal')
.one('hidden.bs.modal', () => {
resolve($modal.data('modal-result'));
$modal
.data('modal-param', null)
.data('modal-result', null)
})
.modal('show')
});
};
モーダルを開く側は次のように await でモーダルが閉じるのを待ってその結果を得ることが出来ます。
$('#show-modal').on('click', async (ev) => {
console.log('モーダルを表示します');
try {
// モーダルにわたすパラメータ
const param = 'ほげほげ';
// モーダルを表示して閉じるまで待つ
const result = await promisifyModal('#modal', param);
if (result != null) {
// モーダルの結果でなにかする
console.log(`モーダルの結果は ${result} です`);
}
} finally {
// モーダルが閉じた後
console.log('モーダルが閉じました');
}
});
表示されるモーダルの側は次のような HTML と js です。モーダルの表示時は $modal.data('modal-param') でモーダルを開く側から渡されたパラメータが受け取れて、モーダルの結果は $modal.data('modal-result') に入れています。
<div class="modal fade" id="modal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">モーダル</h5> <button type="button" class="close" data-dismiss="modal"> <span>×</span> </button> </div> <div class="modal-body"> <input type="text"> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" data-modal-ok>OK</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">キャンセル</button> </div> </div> </div> </div>
const $modal = $('#modal');
$modal.on('show.bs.modal', (ev) => {
// モーダルに渡されたパラメータでなにかする
const param = $modal.data('modal-param');
$modal.find('input[type="text"]').val(param);
});
$modal.find('[data-modal-ok]').on('click', (ev) => {
// モーダルの結果を設定して閉じる
const result = $modal.find('input[type="text"]').val();
$modal.data('modal-result', result);
$modal.modal('hide');
});