Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

use dispatchEvent to dispatch it and wait until promise resolves

I have a custom build modal that has to stop executing any code after it when displayed. For me, this is not a problem when I call it directly (I can handle that) but the problem is when I have to use dispatchEvent on the related element. I’ve constructed the basic example here:

const modal = document.getElementById("myModal");
const btn = document.getElementById("myBtn");
const span = document.getElementsByClassName("close")[0];

btn.onclick = async function() {
  modal.style.display = "block";
  return new Promise(resolve => {
    span.onclick = async function() {
      modal.style.display = "none";
      return await true;
    };
  });
};

(async () => {

  btn.style.color = "black";

  const event = new Event('click');
  await btn.dispatchEvent(event);
  
  btn.style.color = "red";
  
})();
.modal {
  display: none; 
  position: fixed; 
  z-index: 1; 
  left: 0;
  top: 0;
  width: 100%; 
  height: 100%; 
  overflow: auto; 
  background-color: rgb(0,0,0);
  background-color: rgba(0,0,0,0.4);
}

.modal-content {
  background-color: #fefefe;
  margin: 15% auto;
  padding: 20px;
  border: 1px solid #888;
  width: 80%; 
}


.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}
<button id="myBtn">Open Modal and wait (Note: this should't be red before closing modal)</button>

<div id="myModal" class="modal">

  <div class="modal-content">
    <span class="close">&times;</span>
    <p>Some text in the Modal..</p>
  </div>

</div>

How can btn.dispatchEvent(event) be awaited?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

There are a couple of issues there:

  1. It doesn’t make any sense to use async functions as DOM event listeners. The DOM does nothing with the promise that is returned.
  2. Avoid the explicit promise construction anti-pattern — async functions always return promises, you don’t need to construct one unless you need an explicit resolve or reject function.
  3. You’ll need to coordinate outside of the DOM event system, since dispatchEvent won’t return the promise you’re creating.

For instance, you can have a modalPromise and modalResolve that you set up initially like this:

let modalPromise = Promise.resolve();
let modalResolve = null;

…and then update like this when showing the modal:

modalPromise = modalPromise.then(() => {
    return new Promise((resolve) => {
        modalResolve = resolve;
    });
});

Then you await that after showing the modal.

Here’s an idea (I’ve also updated it to use modern event handling, and to not use var — var has no place in modern JavaScript code):

const modal = document.getElementById("myModal");
const btn = document.getElementById("myBtn");
const span = document.getElementsByClassName("close")[0];

let modalPromise = Promise.resolve();
let modalResolve = () => {};

span.addEventListener("click", function () {
    modal.style.display = "none";
    if (modalResolve) {
        modalResolve();
        modalResolve = null;
    }
});

btn.addEventListener("click", function () {
    modal.style.display = "block";
    modalPromise = modalPromise.then(() => {
        return new Promise((resolve) => {
            modalResolve = resolve;
        });
    });
});

(async () => {
    btn.style.color = "black";

    const event = new Event("click");
    btn.dispatchEvent(event);
    await modalPromise;

    btn.style.color = "red";
})();
.modal {
  display: none; 
  position: fixed; 
  z-index: 1; 
  left: 0;
  top: 0;
  width: 100%; 
  height: 100%; 
  overflow: auto; 
  background-color: rgb(0,0,0);
  background-color: rgba(0,0,0,0.4);
}

.modal-content {
  background-color: #fefefe;
  margin: 15% auto;
  padding: 20px;
  border: 1px solid #888;
  width: 80%; 
}


.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}
<button id="myBtn">Open Modal and wait (Note: this should't be red before closing modal)</button>

<div id="myModal" class="modal">

  <div class="modal-content">
    <span class="close">&times;</span>
    <p>Some text in the Modal..</p>
  </div>

</div>

That’s just a sketch, you’ll want to harden it against issues like trying to show the modal twice overlapping, etc.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading