0

I need to create a small delay in this for loop:

for (i = 1; i <= cloneIndex; i++) {
                        var myElem = document.getElementById('form' + i);
                        if (myElem != null) {
                            function postData() {
                                return {
                                udd: document.getElementById('udd').value,
                                data: date_in,
                                hora_ini: hour_in,
                                hora_fim: hour_out,
                                cat: $('#form' + i).find('select[id="cat"]').val(),
                                m1: $('#form' + i).find('select[id="q1"]').val(),
                                m2: $('#form' + i).find('select[id="q2"]').val(),
                                m3: $('#form' + i).find('select[id="q3"]').val(),
                                m4: $('#form' + i).find('select[id="q4"]').val(),
                                m5: $('#form' + i).find('select[id="q5"]').val()
                                }
                            }

                            var newItem = postData();
                            $2sxc(@Dnn.Module.ModuleID).webApi.post('app/auto/content/audits', {}, newItem);
                        }
            }

Following stackoverflow examples, I tried this solution:

for (i = 1; i <= cloneIndex; i++) {
                (function(i){
                    setTimeout(function(){
                        var myElem = document.getElementById('form' + i);
                        if (myElem != null) {
                            function postData() {
                                return {
                                udd: document.getElementById('udd').value,
                                data: date_in,
                                hora_ini: hour_in,
                                hora_fim: hour_out,
                                cat: $('#form' + i).find('select[id="cat"]').val(),
                                m1: $('#form' + i).find('select[id="q1"]').val(),
                                m2: $('#form' + i).find('select[id="q2"]').val(),
                                m3: $('#form' + i).find('select[id="q3"]').val(),
                                m4: $('#form' + i).find('select[id="q4"]').val(),
                                m5: $('#form' + i).find('select[id="q5"]').val()
                                }
                            }

                            var newItem = postData();
                            $2sxc(Dnn.Module.ModuleID).webApi.post('app/auto/content/audits', {}, newItem);
                        }
                    }, 1000 * i);
                }(i));
            }

However this breaks the function inside. It seems myElem is now always null. Too many "i"s? How can I fix this?

6
  • A for loop will run almost immediately to the end. Creating such delays is not a simple matter. Have a look at my answer here: stackoverflow.com/a/37563825/5768908 Commented Oct 29, 2017 at 23:51
  • In wich scope is your variable i declared? (explicitely or implicitely) And did you check the value of i when the function is executed? Commented Oct 30, 2017 at 0:00
  • Also doesn't work Gerard. "i" is just used for the loop. Without the delay code, the original code works fine ( pastebin.mozilla.org/9071510 ), it cycles through form1, form2, etc. I only need the delay since the server can't handle 10 posts simultaneously. Commented Oct 30, 2017 at 0:14
  • @Bergi How is this a duplicate? Did you even read it? That solution does not work! Commented Oct 30, 2017 at 8:16
  • Oops, I looked like you were having issues with the asynchrony. Regarding your question why myElem is null, we don't know the rest of your code or your page markup. It certainly looks like the #form1… elements that document.getElementById is selecting do exist in your document when the loop is running, but not later when the timeout callbacks run. Commented Oct 30, 2017 at 16:40

2 Answers 2

1

You need to define the variable inside the closure for it to be unique to each iteration:

for (var i = 1; i < 10; i++) {
  (function() {
    var k = i; // <-- k will be different for each iteration, because it was declared inside the closure. i was defined outside the closure.
    setTimeout(function() {
      console.log("Delayed: ", i, k)
    }, i * 1000)
  }());
}

...or else include i in the closure definition:

for (var i = 1; i < 10; i++) {
  (function(i) {
    setTimeout(function() {
      console.log("Delayed: ", i)
    }, i * 1000)
  }(i));
}

Sign up to request clarification or add additional context in comments.

Comments

0

Nevermind. The reason the code did not work was simple. The rest of the code below did not wait for the delayed loop to end, so it actually broke the function.

This fixed it (placed inside the setTimeout function):

k++;
if (k == cloneIndex) {rest of the code that needs the loop to end}

2 Comments

Beware, you're effectively defining a global variable k here and incrementing it inside the setTimeout -- if you were to run this loop a second time it would start at whatever value it left off at the first time around.
That's the point. It only increases after each delayed loop. But knows the count outside it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.