[Rails]ブラウザのデフォルト確認ダイアログをカスタマイズする
はじめに
turbo_confirm
を使う際に表示される確認ダイアログをカスタマイズしていきます。
<%= link_to "削除", @post, data: {
turbo_method: :delete,
turbo_confirm: "本当に削除しますか?" } %>
デフォルトのブラウザダイアログ:
環境
Ruby 3.2.1
Rails 7.0.8
tl;dr
-
Turbo.setConfirmMethod
をう -
<dialog>
タグを使う - ダイアログの表示をカスタマイズする
Turbo.setConfirmMethod
を使ってブラウザのデフォルトの確認ダイアログをカスタマイズする
Turbo.setConfirmMethod(() => {
return new Promise((resolve, reject) => {
// ダイアログ
// 確認, resolve(true)
// キャンセル, resolve(false)
})
})
Turbo.setConfirmMethod
メソッドを使用して、カスタムの確認メソッドを設定します。このメソッドはモーダルダイアログを表示し、ユーザーが確認またはキャンセルするまでPromiseを解決しません。
確認ダイアログを表示する前に、新しいPromiseを作成されます。このPromiseは、確認またはキャンセルに基づいて解決されます。
ダイアログが確認された場合、resolve(true)
を呼び出し、Promiseをtrue
で解決します。これで確認が行われます。
ダイアログがキャンセルされた場合、resolve(false)
を呼び出し、Promiseをfalse
で解決します。これでキャンセルが行われます。
<dialog>
タグを使う
HTMLネイティブの <dialog>
タグを使うことができます。<body>
タグの直下に作成していきます。
<dialog id="turbo-confirm">
<form method="dialog">
<h3>投稿の削除</h3>
<p>削除しますか?</p>
<button value="cancel">キャンセル</button>
<button value="confirm">削除</button>
</form>
</dialog>
method="dialog"
は、 <form>
の既定の GET メソッドを上書きします。
Turbo.setConfirmMethod(()=>{
let dialog = document.getElementById("turbo-confirm");
dialog.showModal();
return new Promise((resolve, reject) =>{
dialog.addEventListener("close", ()=>{
resolve(dialog.returnValue == "confirm")
}, { once: true })
})
})
dialog.showModal()
を呼び出して、モーダルダイアログを表示します。
新しいPromiseを作成し、そのPromiseはダイアログが閉じられたときに解決されます。dialog.addEventListener("close", ...)
を使用して、ダイアログが閉じられたときに呼び出されるリスナーを登録します。
resolve(dialog.returnValue == "confirm")
を呼び出してPromiseを解決します。ダイアログのreturnValue
プロパティが "confirm" の場合、Promiseはtrue
で解決され、それ以外の場合はfalse
で解決されます。
{ once: true }
は、JavaScriptのイベントリスナーに対してオプションとして指定できる設定です。この設定は、特定のイベントハンドラーが1度だけ実行されるようにするために使用されます。
通常、イベントハンドラーはイベントが発生するたびに実行されます。しかし、{ once: true }
オプションを指定すると、指定されたイベントハンドラーは最初の一度だけ実行され、その後は自動的に削除されます。一度だけの処理を実装するには便利です。
デフォルトのダイアログよりこちらのモーダルが表示されました。
ダイアログの表示をカスタマイズする
ダイアログの再利用性を向上するために中身やCSSをボタンによって動的に表示できるように設定していきます。
ダイアログの中身をそれぞれ取得することができます。
Turbo.setConfirmMethod((message, element,submitter)=>{
console.log(message, element,submitter);
})
こうやってダイアログの中身を取得することができました。
# message
本当に削除しますか
# element
<form class="button_to" method="post" action="/posts/12"><input type="hidden" name="_method" value="delete" autocomplete="off"><button data-turbo-confirm="本当に削除しますか" type="submit">削除</button><input type="hidden" name="authenticity_token" value="QmANbOvbyInCdNxBynW8tQWFTLT4iANE7Q2rs8b8WnqBy2RXkbiR6Kw_iB7mzaerxTFVjbpm4V522eEKCcy2XQ" autocomplete="off"></form>
# submitter
<button data-turbo-confirm="本当に削除しますか" type="submit">削除</button>
なので、ダイアログのタイトル、本文、ボタンなどをturbo
属性で設定すれば動的に表示することができます。
<%= button_to '削除', @post, method: :delete, class: '',
data: { turbo_confirm: '本当に削除しますか?', // 本文
turbo_confirm_title: '投稿の削除', // タイトル
turbo_confirm_button_class_list: 'bg-red-500' // ボタンのCSS }
%>
getAttribute
でそれぞれの属性の値を取得し、dialog
のコンテンツに代入します。
Turbo.setConfirmMethod((message, element,submitter)=>{
console.log(message, element,submitter);
dialog.querySelector("p").textContent = message; // 本文
dialog.querySelector("h3").textContent = submitter.getAttribute('data-turbo-confirm-title'); // タイトル
dialog.querySelector('button[value="confirm"]').classList = submitter.getAttribute('data-turbo-confirm-button-class-list'); // ボタンのCSS
dialog.showModal();
})
終わりに
ブラウザのデフォルトのダイアログをカスタマイズすることができましたー
CSSでスタイリングをすればアプリの雰囲気に合う確認ダイアログを簡単に作れるのでこれからも活用していきたいと思います!
Discussion