user11703419
user11703419

Reputation:

How do I run code after a setTimeout() is run?

I need the

event.target.innerHTML = FULL_HEART
event.target.setAttribute('class', 'like-glyph activated-heart')

after the displayError() setTimeout interval is completed in the scenario that the mimicServerCall() catches an error.

document.addEventListener('DOMContentLoaded', () => {
  const likeButtons = document.querySelectorAll('.like-glyph');
  const modal = document.getElementById('modal');

  function displayError() {
    modal.removeAttribute('class');
    setTimeout(function(){ modal.setAttribute('class','hidden') }, 3000);
  };

  function likifyMe(button) {
    button.addEventListener('click', (event) => {
      if (event.target.innerHTML === EMPTY_HEART) {
        mimicServerCall().then(() => {}).catch(() => {displayError()});
        event.target.innerHTML = FULL_HEART
        event.target.setAttribute('class', 'like-glyph activated-heart')
      } else {
        event.target.innerHTML = EMPTY_HEART
        event.target.setAttribute('class', 'like-glyph')
      }
    });
  };

  likeButtons.forEach(button => {
    likifyMe(button)
  });

});

Is there a way to achieve this?

Upvotes: 0

Views: 209

Answers (2)

Aaron Plocharczyk
Aaron Plocharczyk

Reputation: 2842

That's what a callback is for:

document.addEventListener('DOMContentLoaded', () => {
  const likeButtons = document.querySelectorAll('.like-glyph');
  const modal = document.getElementById('modal');

  function displayError(callback) {
    modal.removeAttribute('class');
    setTimeout(function(){
        modal.setAttribute('class','hidden');
        callback();
    }, 3000);
  };

  function likifyMe(button) {
    button.addEventListener('click', (event) => {
      if (event.target.innerHTML === EMPTY_HEART) {
        mimicServerCall().then(() => {
            event.target.innerHTML = FULL_HEART;
            event.target.setAttribute('class', 'like-glyph activated-heart');
        }).catch(() => {
            displayError(function(){
                event.target.innerHTML = FULL_HEART;
                event.target.setAttribute('class', 'like-glyph activated-heart');
            });
        });
      } else {
        event.target.innerHTML = EMPTY_HEART
        event.target.setAttribute('class', 'like-glyph')
      }
    });
  };

  likeButtons.forEach(button => {
    likifyMe(button)
  });
});

Upvotes: 1

Klaycon
Klaycon

Reputation: 11080

Leverage the following behavior of promise chaining detailed by MDN:

It's possible to chain after a failure, i.e. a catch, which is useful to accomplish new actions even after an action failed in the chain.

You can rewrite the block in question to this (notice it's .catch().then()):

      if (event.target.innerHTML === EMPTY_HEART) {
        mimicServerCall().catch(() => displayError()).then(() => {
          event.target.innerHTML = FULL_HEART;
          event.target.setAttribute('class', 'like-glyph activated-heart');
        });
      } else { 

Then, just have displayError() return a promise that resolves with the timeout:

  function displayError() {
    return new Promise((resolve,reject) => {
      modal.removeAttribute('class');
      setTimeout(() => {
        modal.setAttribute('class','hidden');
        resolve();
      }, 3000);
    });
  };

The resulting behavior is that your code to activate the heart is guaranteed to happen in the event of either success or failure, but if it did fail, it will wait the three seconds for the setTimeout to execute. This is thanks to promise chaining, which will wait for the promise returned by displayError() to resolve before executing the following .then() callback.

Upvotes: 1

Related Questions