ttmt
ttmt

Reputation: 4984

javascript - function only works on second call

I have a demo here

I have a bar made up of blocks with a marker on top and an input field

Inputting numbers in the input field will slide the marker to that percent

The blocks should change color when the marker is over that block.

This works but the blocks only change color after the marker has moved to another block or the enter is clicked again.

Why doesn't the block change color when the marker moves to that block.

const marker = document.querySelector('.bar-marker');
const bars = document.querySelectorAll('.bar-item');
const input = document.querySelector('.value');

(function() {

  input.addEventListener("keyup", (event) => {
    event.preventDefault();
    if (event.keyCode === 13) {
      const inputVal = document.querySelector('.value').value;
      moveBar(inputVal)
    }    
  })

  function moveBar(val){
    marker.style.left = val + '%';
    for(let i=0; i<=bars.length; i++){
      bars[i].classList.remove('selected')
      if(marker.offsetLeft > 
        bars[i].offsetLeft && marker.offsetLeft < 
        bars[i].offsetWidth+bars[i].offsetLeft){
        bars[i].classList.add('selected')
      }
    }
  }

})();

Upvotes: 1

Views: 197

Answers (2)

Martin L. Brink
Martin L. Brink

Reputation: 507

I chose to separate the classList.remove and the classList.add, so as soon as the new value is entered, the color bars reset immediately and then change once the marker stops:

const marker = document.querySelector('.bar-marker');
const bars = document.querySelectorAll('.bar-item');
const input = document.querySelector('.value');

(function() {

  input.addEventListener("keyup", (event) => {
    event.preventDefault();
    if (event.keyCode === 13) {
      const inputVal = document.querySelector('.value').value;
      moveBar(inputVal)
    }    
  })

  function moveBar(val){
    marker.style.left = val + '%';
    for(let i=0; i<bars.length; i++){
      bars[i].classList.remove('selected')
    }
    setTimeout(function() {
      for (let i=0; i < bars.length; i++) {
        if(marker.offsetLeft > 
          bars[i].offsetLeft && marker.offsetLeft < 
          bars[i].offsetWidth+bars[i].offsetLeft){
          bars[i].classList.add('selected')
        }
      }
    }, 2000)
  }

})();

Upvotes: 2

raman
raman

Reputation: 980

its because you have a 2s animation transition for the slider which mean marker.offsetLeft will have the value of starting point of the slider because of the 2s delay for reaching its destination. Solution would be to wait for 2s so that the animation can end and then run the script.

Using setTimeout of 2.1s could work.

function moveBar(val){
    marker.style.left = val + '%';
    setTimeout(function(){ 
      for(let i=0; i<=bars.length; i++){
        bars[i].classList.remove('selected')
        if(marker.offsetLeft > 
          bars[i].offsetLeft && marker.offsetLeft < 
          bars[i].offsetWidth+bars[i].offsetLeft){
          bars[i].classList.add('selected')
        }
      }
    }, 2100);
  }

Upvotes: 4

Related Questions