はじめに
javascript にはconfirm
というメソッドが用意されており、制御フローの条件として使用することができます。
ダイアログが表示され、「OK」「キャンセル」を選ぶことで処理を実行したり中断したりできる大変便利な機能です。
- コード例
if (confirm("よろしいですか?")) {
alert("OKが押されました。");
} else {
alert("キャンセルが押されました。");
}
- UI
見ての通り簡素な UI で、選択肢の文言を変えることなどはできません。
そこで自作の confirm 関数を作成してみました。
仕様
- 任意の文言を受け付ける。
- 制御フロー内で条件として使用できる。
- 処理待ちを行う関係で非同期関数とする。
表面上の仕様は至ってシンプルなものになります。
ユーザーの入力を待ち、制御フローの中で条件として使用できる。
組み込みの confirm と同様の使い心地を実現できればそれで OK です。
- コード例
if (await confirmAsync("よろしいですか?")) {
alert("OKが押されました。");
} else {
alert("キャンセルが押されました。");
}
設計
-
dialog
要素にて UI を作成する。 - confirmAsync 関数を実行することでモーダル形式でダイアログを表示する。
- OK ボタンをクリックしたら
Promise<true>
を返却してダイアログを閉じる。 - キャンセルボタンをクリックしたら
Promise<false>
を返却してダイアログを閉じる。
ダイアログを自作する場合、一般的にはdiv
要素が使われているのではないでしょうか。
今回はあえてdialog
要素を使用していこうと思います。
ブラウザーの互換性に一抹の不安が残りますが、Google Chrome で動作するので良しとします。
実装
ダイアログ本体
<dialog id="dialog">
<p id="message"></p>
<button id="button-ok">OK</button>
<button id="button-cancel">キャンセル</button>
</dialog>
装飾していない生の HTML です。
confirmAsync 関数
自分で作っておいて言うのもアレですが、結構ややこしいのでいくつかの手順に分割して紹介します。
手順①
- 表示メッセージの受け取り/設定を行う、
- ダイアログを表示する。
- 固定で
Promise<true>
を返却する。
const confirmAsync = async message => {
document.getElementById("message").innerText = message;
document.getElementById("dialog").showModal();
return new Promise(resolve => resolve(true));
};
手順②
- OK ボタン、キャンセルボタンにクリックイベントを設定する。
- OK ボタンがクリックされたら
Promise<true>
を返却してダイアログを閉じる。 - キャンセルボタンがクリックされたら
Promise<false>
を返却してダイアログを閉じる。
const confirmAsync = async message => {
document.getElementById("message").innerText = message;
document.getElementById("dialog").showModal();
return new Promise(resolve => {
document.getElementById("button-ok").addEventListener("click", () => {
document.getElementById("dialog").close();
resolve(true);
});
document.getElementById("button-cancel").addEventListener("click", () => {
document.getElementById("dialog").close();
resolve(false);
});
});
};
この時点でそれなりに昨日は完成していますが、もう少し工夫していきます。
手順③
- クリックイベントを括りだす。
- OK ボタン用、キャンセルボタン用のイベントを作成する。
(※次の手順で removeEventListener に設定するためです。) - OK ボタンがクリックされたら
okEvent
を実行する。 - キャンセルボタンがクリックされたら
cancelEvent
を実行する。
const confirmAsync = async message => {
document.getElementById("message").innerText = message;
document.getElementById("dialog").showModal();
return new Promise(resolve => {
const eventBase = flag => () => {
document.getElementById("dialog").close();
resolve(flag);
};
const okEvent = eventBase(true);
const cancelEvent = eventBase(false);
document.getElementById("button-ok").addEventListener("click", okEvent);
document.getElementById("button-cancel").addEventListener("click", cancelEvent);
});
};
手順④
- OK ボタンからクリックイベントを削除する。
- キャンセルボタンからクリックイベントを削除する。
const confirmAsync = async message => {
document.getElementById("message").innerText = message;
document.getElementById("dialog").showModal();
return new Promise(resolve => {
const eventBase = flag => () => {
document.getElementById("dialog").close();
document.getElementById("button-ok").removeEventListener("click", okEvent);
document.getElementById("button-cancel").removeEventListener("click", cancelEvent);
resolve(flag);
};
const okEvent = eventBase(true);
const cancelEvent = eventBase(false);
document.getElementById("button-ok").addEventListener("click", okEvent);
document.getElementById("button-cancel").addEventListener("click", cancelEvent);
});
};
ダイアログの実装手順は以上となります。
実行例
あとは実際に呼び出すだけです。
組み込みの confirm を呼び出すときと同様の感覚で実装できます。
const handleClicked = async () => {
if (await confirmAsync("よろしいですか?")) {
alert("OKが押されました。");
} else {
alert("キャンセルが押されました。");
}
};
<button onclick="handleClicked()">確認</button>
装飾など
UI 自体はただの HTML なので、通常通り css で装飾することができます。
以下は Bootstrap を用いた例です。