I have a button like this:
<.button phx-click="delete-everything" phx-disable-with="Please wait...">
Delete Everything
</.button>
and I want to gracefully handle “accidental” clicks.
So I have this very simple way to “confirm user action” that I will share.
First, add this JS to app.js
:
import ultraConfirm from "./ultraConfirm";
window.addEventListener("ultra-confirm", ultraConfirm.confirmAndExec);
Then create a file ultraConfirm.js
beside app.js
with this code:
const execAttr = (el, attrName) => {
const attr = el.getAttribute(attrName);
attr && liveSocket.execJS(el, attr);
};
const confirmAndExec = ({ detail, srcElement }) => {
const { message } = detail;
if (confirm(message || "Are you sure?")) {
execAttr(srcElement, "phx-ultra-confirm-ok");
} else {
execAttr(srcElement, "phx-ultra-confirm-cancel");
}
};
export default { confirmAndExec };
You can see this is using Javascript’s confirm
, which is like alert
except the user can OK
or Cancel
.
Now all I need to do is rewrite my button like this:
<.button
phx-click={
JS.dispatch("ultra-confirm",
detail: %{message: "Are you sure you want to delete everything?"}
)
}
phx-ultra-confirm-ok={JS.push("delete-everything")}
phx-disable-with="Please wait..."
>
Delete Everything
</.button>
You can send a payload (what is usually called params
in the handle_event/3
callback) with the JS.push
call. Just check the docs for that function (Phoenix.LiveView.JS — Phoenix LiveView v0.20.17).
Note that I named the attribute phx-ultra-confirm-ok
. I did this because if I named it, e.g. ultra-confirm-ok
then core components like button
will complain about “unexpected attribute”.
Note finally that the phx-disable-with
works as we would expect it too.