Toniq
Toniq

Reputation: 5006

JavaScript setTimeout parameters and selectors

I am trying to select elements in the loop and pass them to setTimeout.

Why doesn't the following work as it is supposed to?

Is it because el.querySelector('.b') is slower than setTimeout?

var ids = document.querySelectorAll('.a'),
  span

ids.forEach(el => {

  span = el.querySelector('.b')
  setTimeout(function() {
    span.classList.add('visible');
  }, 20, span);
})
.visible{
  color:red;
}
<p class="a"><span class="b">1</span></p>
<p class="a"><span class="b">2</span></p>
<p class="a"><span class="b">3</span></p>

Upvotes: 0

Views: 95

Answers (2)

Konrad
Konrad

Reputation: 24671

Just don't use var and declare variables in their scope

const ids = document.querySelectorAll('.a')

ids.forEach(el => {
  const span = el.querySelector('.b')
  setTimeout(function() {
    span.classList.add('visible');
  }, 20);
})
.visible {
  color: red;
}
<p class="a"><span class="b">1</span></p>
<p class="a"><span class="b">2</span></p>
<p class="a"><span class="b">3</span></p>

Upvotes: 2

Felix G
Felix G

Reputation: 861

In the code you provided, the span variable is overwritten on each iteration of the forEach loop, so when the callback function is executed, it will always reference the same element (the last one selected by querySelector). To fix this, you can move the querySelector call inside the callback function, like this:

var ids = document.querySelectorAll('.a'),
  span
  
ids.forEach(el => {
  setTimeout(function() {
    var span = el.querySelector('.b')
    span.classList.add('visible');
  }, 2000);
})
.visible{
  color:red;
}
<p class="a"><span class="b">1</span></p>
<p class="a"><span class="b">2</span></p>
<p class="a"><span class="b">3</span></p>

This should work as expected. I've increased the delay to make the change more visible.

Upvotes: 2

Related Questions