0

Below is a JavaScript file:

var ToastBtnClicks = 0;
function ShowToast(ToastText){
  ToastBtnClicks++;
  $('#ToastContainer').append("<div class='ToastContainerChild' id='ToastContainerChild"+ ToastBtnClicks +"'>"+ToastText+"</div><br>");
  //document.getElementById("ToastContainer").className = "show";
  setTimeout(function(){ $("#ToastContainerChild"+ToastBtnClicks).remove(); }, 2000);
}

Whenever the ShowToast function gets called, a new div element gets appended to the element #ToastContainer. That process is working perfectly. Also, after 2 seconds of calling the function, that new element gets removed using setTimeOut method. The problem I'm facing, is that if we call that function multiple times(without waiting for the rest to get removed), and after some seconds if we stop continuously calling that function, only the lastly appended element gets removed(after 2 secs). Why? I want the function to remove every appeded elements from the webpage, right 2secs after their creation(or appendation). How do I do it ? And sorry for my bad English, if it is...

  • 3
    Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – JJJ Apr 16 '18 at 16:25
  • You have one variable called `ToastBtnClicks`, that gets updated, it's always going to equal the last number,. You need a snapshot of the number inside your function, just create another var say called, `toastNo` and set it the `ToastBtnClicks` and use `toastNo` in your setTimeout callback. – Keith Apr 16 '18 at 16:27
  • 1
    @JJJ: This isn't a closure in a loop problem. It's just a standard data race. –  Apr 16 '18 at 16:27
  • ...to correct myself, it's a "race condition". JS doesn't have data races. –  Apr 16 '18 at 17:14

1 Answers1

0

Make a local variable to reference the index used for the element created so that it's certain to remove the correct one. This is needed because your counter is shared, so if you click within two seconds, the timer will be referencing the incremented value instead of the original.

var ToastBtnClicks = 0;

function ShowToast(ToastText){
  var x = ++ToastBtnClicks; // Notice the prefix ++

  $('#ToastContainer').append("<div class='ToastContainerChild' id='ToastContainerChild"+ x +"'>"+ToastText+"</div><br>");

  setTimeout(function(){ $("#ToastContainerChild"+x).remove(); }, 2000);
}

And it would probably make more sense just to reference the new element anyway. Then you don't need the ID, assuming that was its only purpose.

function ShowToast(ToastText){
  var el = $("<div class='ToastContainerChild'>"+ToastText+"</div><br>");
  el.appendTo('#ToastContainer');

  setTimeout(function(){ el.remove(); }, 2000);
}

Note that this will also remove the <br> elements, which I would assume would be desired. Otherwise do el.first().remove().