Search code examples
javascriptjqueryhtmlcssfade

jQuery setTimeout $this.remove() Overlapping for Multiple Elements


I have 2 separate <div> elements that have a similar invoke button which adds a transparent overlay message. My issue is that when I click both buttons in rapid succession, or the same button twice before the timeout expires, the overlay is only removed once (instead of stacking with however many overlays are added). I would appreciate any help in solving this problem, as well as if someone can help me tidy up my code (it seems grossly inefficient).

JSFiddle: http://jsfiddle.net/Hybridx24/733ueao4/

$(document).on('click', '#invoke', function(e) {

    $this = $(this);

    $cardOverlay = $("<div style='transition: background 0.2s linear' class='card-overlay'><span style='color:white;position:relative;top:40%;font-weight:bold'>Success!</span></div>");

    $this.parent('.card-shadow').append($cardOverlay);

    $cardOverlay.height('100%').css({
        'opacity' : 1,
        'position': 'absolute',
        'top': 0,
        'left': 0,
        'background': 'rgba(0, 0, 0, 0.6)',
        'width': '100%',
        'z-index': 1,
        'border-radius': '6px',
        'text-align': 'center'
    });

    setTimeout(function() {
        $cardOverlay.fadeOut("normal", function(){
            $(this).remove();
        })
    }, 2000)
});

Solution

  • You forgot var before $cardOverlay, therefore $cardOverlay is defined in the global scope and is the same variable for every time your handler runs. You're overwriting its value each time you click on #invoke which means when the setTimeout runs, it always refers to the newest assignment to $cardOverlay and so the reference to the old overlay is lost. Change:

    $cardOverlay = $("<div style='transition: background 0.2s linear' class='card-overlay'><span style='color:white;position:relative;top:40%;font-weight:bold'>Success!</span></div>");
    

    to

    var $cardOverlay = $("<div style='transition: background 0.2s linear' class='card-overlay'><span style='color:white;position:relative;top:40%;font-weight:bold'>Success!</span></div>");
    

    For similar reasons, you also probably want to add var before $this = $(this); as well. Remember, although you're allowed to omit var in javascript, each time you do the variable is defined in the global scope, and other methods can come along (or the same method could run a second time) and interfere with the values of your variables. Generally speaking if you are using a variable that you only want to have access to within a certain scope, you should define it with var in that scope, which in your case is your handler function.