I’m attaching confirmation <dialog>
s to any forms that need them with
const forms = document.querySelectorAll("form[data-confirm]");
forms.forEach((form) => {
const confirm = document.createElement("dialog");
const message = document.createElement("p");
const cancel = document.createElement("button");
const accept = document.createElement("button");
message.innerText = form.dataset.confirm;
cancel.innerText = form.dataset.cancel;
accept.innerText = form.dataset.accept;
confirm.appendChild(message);
confirm.appendChild(cancel);
confirm.appendChild(accept);
form.appendChild(confirm);
form.onsubmit = (event) => {
event.preventDefault();
confirm.showModal();
}
cancel.onclick = () => {
console.log(confirm.close)
confirm.close();
}
accept.onclick = () => {
form.submit();
}
});
This seems to work well, apart from the close()
method, which does nothing and throws no error. Logging the function to the console shows
function close()
length: 0
name: "close"
<prototype>: function ()
in Firefox, while Edge & Chrome show
f close() { [native code] }
Changing the call to hide()
as a test predictably results in
Uncaught TypeError: confirm.hide is not a function
Logging the dialog itself shows that we’re dealing with the right DOM object:
...
cancel.onclick = () => {
console.log(confirm)
confirm.close();
}
> <dialog open="">
...
<prototype>: HTMLDialogElementPrototype { show: show(), showModal: showModal(), close: close(), … }
There are no other dialogs on the page. I seem to be the only one who’s run into this problem, which makes me think a facepalm moment is not far off. Can you deliver it?
2
Answers
You also need to prevent the default action of the cancel button – as it’s in the form it’s probably closing the modal but submitting the form again and showing a new modal (if you change the cancel to a span instead of a button, you will see it works without the prevent default):
Every button inside the form will trigger submit when clicked so you are in a submit loop that technically close and reopen your dialog.
To fix this add
event.preventDefault();
inside every button of your dialog: