Adam McGurk
Adam McGurk

Reputation: 476

Force JavaScript to complete animation before moving to next step

I'm building a simple rotator that rotates three pieces of advice for a website. I want it to fade out/in and adding/removing classes to do that. In the JavaScript debugger, it works perfectly, because it is given time to step through all of the calls, but in actual execution, it is very choppy. I understand it's doing that because the script only cares about adding the class, it doesn't care about completing the transition in the class, but I need to know how to get the script to fully finish the transition in the class. Here is the JavaScript:

function rotateAdvice() {
  let nextAdvice;
  const currentAdviceCont = document.querySelector(".advice-show");
  const currentAdvice = currentAdviceCont.id.slice(-1);
  if (currentAdvice >= 2) {
    nextAdvice = document.getElementById("advice-0");
  } else {
    nextAdvice = "advice-"+(parseInt(currentAdvice) + 1);
    nextAdvice = document.getElementById(nextAdvice);
  }
  currentAdviceCont.classList.add("advice");
  currentAdviceCont.classList.remove("advice-show");
  currentAdviceCont.classList.add("no-display");
  nextAdvice.classList.remove("no-display");
  nextAdvice.classList.add("advice-show");
}
// called through this:
setInterval(rotateAdvice, 4000);

And here are the three css classes:

.advice {
    opacity: 0;
    transition: 1s opacity;
}
.advice-show {
    opacity: 1;
    transition: 1s opacity;
}
.no-display {
    display: none;
    visibility: hidden;
}

Upvotes: 0

Views: 239

Answers (2)

Adam McGurk
Adam McGurk

Reputation: 476

I just used a simple event listener for transitionend like this:

  currentAdviceCont.classList.add("advice");
  currentAdviceCont.classList.remove("advice-show");

  currentAdviceCont.addEventListener("transitionend", () => {
    currentAdviceCont.classList.add("no-display");
    nextAdvice.classList.remove("no-display");
    nextAdvice.classList.remove("advice");
    nextAdvice.classList.add("advice-show");});

}

Upvotes: 0

Asons
Asons

Reputation: 87262

You can use its transitionend event to get a more accurate toggle.

Stack snippet

var box1 = document.querySelector(".box.nr1");
var box2 = document.querySelector(".box.nr2");

box1.addEventListener("transitionend", trans_ended, false);
box2.addEventListener("transitionend", trans_ended, false);
setTimeout(function() { box1.classList.add('trans') }, 10);

function trans_ended (e) {
  if (e.type == 'transitionend') {
    if (e.target == box1) {
      box1.classList.remove('trans');
      setTimeout(function() { box2.classList.add('trans') }, 10);
    } else if (e.target == box2) {
      box2.classList.remove('trans');
      setTimeout(function() { box1.classList.add('trans') }, 10);
    }
  }
}
.box {
  position: absolute;
  left: 1em;
  top: 1em;
  width: 5em;
  height: 5em;
  background-color: blue;
  opacity: 0;
  transition: opacity 2s;
}
.box.nr2 {
  background-color: red;
}
.box.trans {
  opacity: 1;
}
<div class="box nr1"></div>
<div class="box nr2"></div>


Another option is to use animation, with which one can do more cool stuff.

Here is another answer of mine, with a simple sample:

Upvotes: 3

Related Questions