0

People, this is really very very odd, I'm getting myself crazy with this. It appears to be very curious.

It's about simply get an element, like a p, or li, for example, make it dissapear, change its text, and reappears.

It works perfect outside a for loop, but inside a for loop, it doesn't works!, and when you need to change x number of elements depending some conditions, loops always has been the way to go.

I prepared a commented fiddle:

http://jsfiddle.net/Reaversword/JYrQ8/

Anyway, I'm gonna write the code here too:

CSS

/*This doesn't matters for the question*/
.Disc
{
    list-style-type:circle;
list-style-type:disc;
list-style-position:outside;
}

#clk
{
    color:blue;
    background:red;
    width:60px;
    height:20px;
}

JAVASCRIPT

//Document Ready function
$(document).ready (function (){createAll();});

//Function that creates a Div for click, and some Unordered List elements
function createAll()
{
    var clk=document.createElement("div");
    clk.id="clk";
    clk.onclick=function(){Disreappear();};
    clk.innerHTML = "ClickMe!";
    $(document.body).append(clk);

    var Father=document.createElement("div");
    $(document.body).append(Father);

    var MainList=document.createElement("li");
    MainList.id="idMainList";
    MainList.innerHTML="<a href='#home' style='text-decoration:none;'>MainList</a>";
    Father.appendChild(MainList);

    //Now another nested one:
    var NewNested=document.createElement("ul");
    Father.appendChild(NewNested);

        //And now, Nested Lis
        var NN1=document.createElement("li");
        NN1.id="idNN1";
        NN1.className="Disc";
        NN1.innerHTML="<a href='http:www.google.com' style='text-decoration:none;'>GoogleCom</a>";
        NewNested.appendChild(NN1);

        var NN2=document.createElement("li");
        NN2.id="idNN2";
        NN2.className="Disc";
        NN2.innerHTML="<a href='http:www.google.es' style='text-decoration:none;'>GoogleEs</a>";
        NewNested.appendChild(NN2);

        var NN3=document.createElement("li");
        NN3.id="idNN3";
        NN3.className="Disc";
        NN3.innerHTML="<a href='http:www.google.it' style='text-decoration:none;'>GoogleIt</a>";
        NewNested.appendChild(NN3);

        var NN4=document.createElement("li");
        NN4.id="idNN4";
        NN4.className="Disc";
        NN4.innerHTML="<a href='http:www.google.de' style='text-decoration:none;'>GoogleDe</a>";
        NewNested.appendChild(NN4);

        var NN5=document.createElement("li");
        NN5.id="idNN5";
        NN5.className="Disc";
        NN5.innerHTML="<a href='http:www.google.fr' style='text-decoration:none;'>GoogleFr</a>";
        NewNested.appendChild(NN5);
}

//Function that dispatches when we click on the div (ClickMe!). There is something I can't understand:
function Disreappear()
{
    //This makes the "MainList" dissapears in 0.2 seconds
    $("#idMainList").css({"opacity":"0.0", "transition":"0.2s", "-webkit-transition":"0.2s"});
    //This changes "MainList" text (nodeValue) after 0.2 secs
    setTimeout(function(){$("#idMainList").text("Hello")}, 200);
    //This makes the "MainList" reappears in 0.2 seconds after 0.2 seconds, (so, after text has changed).
    setTimeout(function(){$("#idMainList").css({"opacity":"1.0", "transition":"0.2s", "-webkit-transition":"0.2s"})}, 200);

    //OK. Now the same, but for 5 elements inside a for loop:
    for (var chg=0; chg<5; chg++)
    {
        //Dissapears
        $("#idNN"+String(chg+1)).css({"opacity":"0.0", "transition":"0.2s", "-webkit-transition":"0.2s"});
        //Text (nodeValue) change
        setTimeout(function(){$("#idNN"+String(chg+1)).text("Hello")}, 200);
        //Reappears (doesn't works and no idea of why!)
        setTimeout(function(){$("#idNN"+String(chg+1)).css({"opacity":"1.0", "transition":"0.2s", "-webkit-transition":"0.2s"})}, 200);
    }
}

I tested with jQuery animate, or jQuery delay. No way to get it working!. Any ideas?. Why last command in the for doesn't works, still when even the code outside the for loop works perfectly?.

Edit: By the way, there is no problem of loop var "chg", if you add an alert function in the for, you'll see how the elements dissapears one by one.

Reaversword
  • 169
  • 1
  • 4
  • 11
  • 1
    You do know you can do: `$(document).ready(createAll)` instead of what you have done. Just a comment. Same with `clk.onclick = Disreapear`. The exception to this is when you have a bunch of arguments that you want to pass to your function. – StackSlave Jan 07 '14 at 00:25
  • Thanks for the point PHPglue, I'll take it present from now on – Reaversword Jan 07 '14 at 00:45

1 Answers1

1

Oh, I love this kind of problems :)

This happens because the chg variable increments quickly to 6, then the setTimeouts execute, and the value of this var is obsolete.

This fixes it:

for (var chg=0; chg<5; chg++)
{
    (function(chg){
        //Dissapears
        $("#idNN"+String(chg+1)).css({"opacity":"0.0", "transition":"0.2s", "-webkit-transition":"0.2s"});
        //Text (nodeValue) change
        setTimeout(function(){$("#idNN"+String(chg+1)).text("Hello")}, 200);
        //Reappears (doesn't works and no idea of why!)
        setTimeout(function(){$("#idNN"+String(chg+1)).css({"opacity":"1.0", "transition":"0.2s", "-webkit-transition":"0.2s"})}, 200);
    })(chg);                
}

jsfiddle: http://jsfiddle.net/edgarinvillegas/JYrQ8/1/

We're introducing a closure, so the chg in the inner function maintains the original value.

EDIT To understand better the solution, you can name the inner and outer chg differently:

for (var i=0; i<5; i++)
{
    (function(chg){
        //Dissapears
        $("#idNN"+String(chg+1)).css(...
    })(i);                
}

The trick is that each step of the loop "creates" a different chg variable, as it's not shared anymore it doesn't get overwritten.

Cheers, from La Paz, Bolivia

Edgar Villegas Alvarado
  • 18,204
  • 2
  • 42
  • 61