skip to Main Content

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


  1. 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):

    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 = event => {
        event.preventDefault();
        confirm.close();
      }
      
      accept.onclick = () => {
        form.submit();
      }
    });
    <form action="#" method="get" data-confirm="confirm" data-cancel="cancel" data-accept="accept">
     <input type="submit" value="submit">
    </form>
    Login or Signup to reply.
  2. 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:

    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 = () => {
        //just add this for fix your problem
        //=================================
        event.preventDefault();
        //================================
        confirm.close();
      }
      accept.onclick = () => {
        //this is not mandatory but is usefull 
        //if you want add some logic inside accept
        //=================================
        event.preventDefault();
        //================================
        form.submit();
      }
    });
    <form data-confirm="confirm" data-cancel="cancel"  data-accept="accept">
    <h2>hero</h2>
    <button>test</button>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search