Brandon Benefield
Brandon Benefield

Reputation: 1672

JavaScript: Code moves too fast, should I write a Promise?

I'm trying to make my web app a little more user friendly, and instead of instantly removing an element I want it to fade away before actually being removed. The problem is my code is running too quickly. While I understand everything is working correctly, I need it to wait for the element to "disappear" before actually being removed. Is this a good example of when to use a Promise or should I use setTimeout()?

Code Overview

check if variables exist
if button is clicked change element opacity (transition: opacity 1s;)
then call deletePostPromise()
then remove the element from the dom

As you can see, I'm even writing my pseudocode as a promise, then.. then...

Specifically, start at row.style.opacity = '0';

if (displayPostWrapper && submitPostBtn) {
  displayPostWrapper.addEventListener('click', e => {
    if (e.target && e.target.nodeName == 'BUTTON') {
      e.preventDefault();

      const {  parentElement } = e.target;
      const row    = parentElement.parentElement.parentElement;
      const form   = parentElement;
      const postID = parentElement.childNodes[3].value;;

      row.style.opacity = '0';

      deletePostPromise('http://localhost/mouthblog/ajax/delete_post.ajax.php', `id=${postID}`)
        .then(() => {
          row.remove();
        });

      // row.remove();
    } // if
  }); // click event

EDIT

JS

const deletePostPromise = (url, postID) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('POST', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('if (xhr.status == 200)');
        resolve();
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send(postID);
  });
}

if (displayPostWrapper && submitPostBtn) {
  displayPostWrapper.addEventListener('click', e => {
    if (e.target && e.target.nodeName == 'BUTTON') {
      e.preventDefault();

      const { parentElement } = e.target;
      const row               = parentElement.parentElement.parentElement;
      const form              = parentElement;
      const postID            = parentElement.childNodes[3].value;;

      row.style.opacity = '0';

      deletePostPromise('http://localhost/mouthblog/ajax/delete_post.ajax.php', `id=${postID}`);

      row.addEventListener("transitionend", function(event) {
        // alert('Done!');
        row.remove();
      }, false);
    } // if
  }); // click event

CSS

.row {
      opacity: 1;
      transition: opacity 5s;
    }

Upvotes: 0

Views: 97

Answers (1)

jfriend00
jfriend00

Reputation: 707376

You can set a listener using the transitionend event that will tell you when the opacity transition has completed and then you can remove the element then.

row.addEventListener("transitionend", function(event) {
  console.log("transition completed, removing row");
  row.remove();
}, false);

You would add this listener right before you change the opacity which triggers the start of the fadeout.

Here's a simple working example that you can run to see it work.

function log(msg) {
    let div = document.createElement("div");
    div.innerHTML = msg;
    document.getElementById("log").appendChild(div);
}

document.getElementById("run").addEventListener("click", function() {
    document.getElementById("test").style.opacity = 0;
});

let test = document.getElementById("test");

test.addEventListener("transitionend", function(e) {
    log(`transitionend for ${e.propertyName}, removing DOM element`)
    test.remove();
});
.fade {
   opacity: 1;
   transition: opacity 2s;
}
<button id="run">
Start Animation
</button>
<div class="fade" id="test">
Some content that will fade out
</div>
<div id="log">

</div>

Upvotes: 1

Related Questions