0

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;
}
Adam McGurk
  • 186
  • 1
  • 19
  • 54
  • 1
    Instead of setInterval, add an event listener for transitionend which calls the rotate method when fired. – delinear Mar 21 '18 at 17:16
  • 1
    Look into the JavaScript event [`transitionEnd`](https://developer.mozilla.org/en-US/docs/Web/Events/transitionend) to trigger your classes in sequence. – chriskirknielsen Mar 21 '18 at 17:17

2 Answers2

3

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:

Asons
  • 84,923
  • 12
  • 110
  • 165
0

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");});

}
Adam McGurk
  • 186
  • 1
  • 19
  • 54