Search code examples
javascriptjqueryhtmlfade

How to force jQuery function to finish fading animation before updating text?


I'm developing a javascript application that receives messages from my python program which is linked to a chat room. The goal is for the javascript application to update the text of an html paragraph to "thank you + user" for each chat message, fade in, delay, then fade out.

My issue is that if I receive several chat messages at once, the paragraph text updates immediately for each chat sender, and doesn't wait for the fading animation.

Right now, for each chat message, I am calling the function below every time I receive a chat line.

function fadeInfadeOutMessage(name) {
    $('#twitchname').html("Thank you <br> " +  name).fadeIn(timeFade[0]).delay(timeFade[1]).fadeOut(timeFade[2])
}

What changes do I need to make to not allow the html to be updated until the fading sequence finishes?


Solution

  • So promises allow you to complete actions and then do something afterwards. So looking at the example below I make my message div promise he wont do anything until his animation queue is complete. The first promise fires immediately because he wasn't doing anything to start. A promise will always fire immediately if there is nothing to do. So no matter how many times I click the button it always waits to complete what it was doing before it starts again.

    Source: https://api.jquery.com/promise/

    Fiddle: https://jsfiddle.net/pxospknj/

    JS:

    // No changes to this function. Its our callback now.
    // The thing that happens after promises complete
    function fadeInfadeOutMessage(name) {
        $('#somemessage').html("Thank you <br> " +  name).fadeIn(1000).delay(1000).fadeOut(1000);
    }
    
    
    $("#somebutton").on("click",
        function () {
        var element = $("#somemessage");
    
        // Make the element promise us that when its done doing whatever
        // its doing it will complete what we just asked it to do which
        // is animate again.
        element.promise().done(
            function () {
            fadeInfadeOutMessage("gary");
          }
        )
      }
    );
    

    HTML:

    <button id="somebutton">go</button>
    <div id="somemessage"></div>
    

    ======================================

    OK, so the default queue is for effects so updating the HTML happens immediately while the animations are queued. Buuuuut if we pass the string in and fake out the queue with a super fast animation and then update the html during the callback before doing our real animations we can pull it off.

    At this point promises aren't even needed because of the default effects queue but they are super powerful when dealing with async code so keep them in mind and read up on them for future use.

    Fiddle: https://jsfiddle.net/pxospknj/4/

    HTML:

    <button id="somebutton">go</button>
    <div id="somemessage"></div>
    

    JS:

    function fadeInfadeOutMessage(name) {
      // Immediate hide so we know its hidden before updating and we can use
      // the callback to update html while taking advantage of the effects queue
      $('#somemessage').hide(0,
        function() {
          $(this).html("Thank you <br> " + name);
        }).fadeIn(1000).delay(1000).fadeOut(1000);
      // Proceed as normal with other animations
    }
    
    // Init our count so we see different strings updating properly
    var count = 0;
    $("#somebutton").on("click",
      function() {
        // Make sure we pass in string so it has scope
        fadeInfadeOutMessage("gary" + count);
        // Update count
        count++;
      }
    );