0

I have this segment of code that allows you set CSS changes on a timed delay. It works perfect except that it only allows you to have one instance, while I need for it to allow many. It currently just takes the last element from the loop and keeps the timeout function. Is there a way to let ALL the timeout functions from this loop to be saved and ran? I'm thinking that it is just that the setTimeout function is being overridden each time rather than being a unique function.

Note: I am getting NO console errors

Javascript (inside an onload function)

  elems = _('[data-timecss]'); //function to return elems via querySelectorAll()
  for (var i=0; i<elems.length; i++) {
     var tempelem = elems[i];
     var c_info = elems[i].dataset.timecss.split(","); //split to get time
     setTimeout(function() {
       var css_e = c_info[1].split(";"); //split to get css properties
       for (var c=0; c<css_e.length; c++) {
         var css_elem = css_e[c].split(":"); //split property and value
         tempelem.style.setProperty(css_elem[0], css_elem[1]); //set value
       }
     }, c_info[0]); //set time
  }

The HTML

<div class="block">
  <p data-timecss="2000,color:green;font-weight:bold;">Change to green after 2000ms</p>
  <p data-timecss="5000,display:none;">Hide this block after 5000ms</p>
</div>

Whichever data-timecss is last, will run correctly. So I can tell that the timeout function is just being overridden each time. Does anyone have any ideas on how to make these unique, but also keep it as dynamic as I have it?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Spencer May
  • 4,266
  • 9
  • 28
  • 48
  • What's in elems? Are you sure it doesn't only contain the second p tag? – evilunix Sep 14 '15 at 14:36
  • You are overwriting tempelem on every iteration so that all timers act on the last one. Because the first timer won't run until the loop has been completed. As Jaromanda X suggests, you'll need closures. – andrrs Sep 14 '15 at 14:38
  • @evilunix yes I am sure. If I put an alert in the function, I can see it is running the setTimeout function twice and grabbing both timecss datasets – Spencer May Sep 14 '15 at 14:38
  • I think you might be creating a closure, so the values of tempelem and c_info are always for the second element. Try passing elems[i] into the anonymous function call inside setTimeout? setTimeout(function(elems[i]... etc? – evilunix Sep 14 '15 at 14:40

1 Answers1

2

you need closure - How do JavaScript closures work?

elems = _('[data-timecss]'); //function to return elems via querySelectorAll()
for (var i=0; i<elems.length; i++) {
    (function(i) { // added this
        var tempelem = elems[i];
        var c_info = elems[i].dataset.timecss.split(","); //split to get time
        setTimeout(function() {
            var css_e = c_info[1].split(";"); //split to get css properties
            for (var c=0; c<css_e.length; c++) {
                var css_elem = css_e[c].split(":"); //split property and value
                tempelem.style.setProperty(css_elem[0], css_elem[1]); //set value
            }
        }, c_info[0]); //set time
    }(i)); // added this
}
Community
  • 1
  • 1
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Genius! I knew about closures but I haven't seen it like this before. Is this `(function(i) { }(i));` basically just putting everything inside of it in a unique function? It works perfect. Thanks! – Spencer May Sep 14 '15 at 14:44