Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery: fadeOut().empty().append(...).fadeIn() doesn't work properly only the first time

I'm struggling to understand why I'm getting the behaviour that I'm seeing. I have a piece of code that aims to fadeOut a container, replace the contents and then fade it back in again when it's done.

I'm using jQuery, so the code looks like this:

var transitionToNewContent = function(container, new_content) {
    container.fadeOut().delay(1000).empty().append(new_content).fadeIn();
};


transitionToNewContent($('#id'), "<p>magic</p>");

The first time that the link that activates this transition is clicked, the content is replaced instantly, then the fadeout happens, then it fades in again.

Every time after that when the link is clicked, I'm seeing the correct behaviour: fadeout, then fadein with the new content.

Any idea why this is happening?

I've attached a complete html file which shows the behaviour:

I'm fairly new to jquery and I'm trying to do things 'the right way'. Any comments regarding style will be appreciated.

<doctype html>
<html>
<head>
  <style type="text/css">
    #main_container {
    width: 800px;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 3em;
    margin-top: 0;
    height: 100%;
    position: relative;
    top: 0px;
    bottom: 0px;
}

#loading {
    float: right;
    position: relative;
    top: 10px;
    left: 10px;
    z-index: 1;
}

#sidebar {
    float: left;
    width: 240px;
    border: #078600 1px dashed;
    position: relative;
    top: 10px;
    left: -250px;
    margin-right: 20px;
    background: #cccccc;
    z-index: 1;
    padding: 10px;
    font-size: 0.65em;
    display: none;
}

#main_content {
    z-index: 0;
    position: absolute;
    top: 0px;
    left: 5px;
    width: 100%;
    height: 100%;
    float: right;
    background: white;
    padding-top: 0;
    padding-bottom: 3em;
    padding-left: 20px;
    border-right: 1px dotted #078600;
    border-left: 1px dotted #078600;
    border-top: 3px solid white;
}

  </style>
  <link rel="stylesheet" type="text/css" href="/main.css" />
</head>
<body>
  <div id="main_container">
    <div id="sidebar"><h1>Sidebar</h1><p>some text</p></div>
    <div id="loading" style="display: none">&nbps;</div>

    <div id="main_content">
      <h1 id="page_title">Title</h1>
      <div id="page_content"><h2>heading</h2><p>Some testing text</p></div>
    </div>
  </div>
  <script type="text/javascript">
var include = function(src) {
    document.write('<script type="text/javascript" src="' + src + '"></scr' + 'ipt>'); 
};

include("http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js");
include("http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js");

var bootStrapSites = function() {
    var sideBar = $('#sidebar');
    sideBar.delay(1000).fadeIn();
    loadSiteList(sideBar);
};

var transitionToNewContent = function(container, new_content) {
    container.fadeOut().delay(1000).empty().append(new_content).fadeIn();
};

var editSite = function(site) {
    transitionToNewContent($('#page_content'), "<p>This is where the magic will happen</p>");
};

var loadSiteList = function(container) {
//    $.getJSON("/sites/list.json", function(data) {

            var data = $.parseJSON('[{"id": "1", "name": "cool name"}]');
        container.empty(container);
        container.append("<h2>new heading</h2>");
        container.append("<ul id='sitesList'></ul>");

        var sitesList = $('#sitesList');
        $.each(data, function(idx, site) {
            var id = 'show_site_id_' + site._id;
            sitesList.append("<li><a id='" + id + "' href='#'>" + site.name + "</a></li>");
            $('#' + id).click(function() {
                editSite(site);
            });
        });
//  });
};
</script>
  <script type="text/javascript">

$(document).ready(function() {
   bootStrapSites();
});

  </script>
</body>
</html>
like image 944
Pieter Breed Avatar asked Apr 02 '11 21:04

Pieter Breed


People also ask

What is fadeIn and fadeOut in jQuery?

The jQuery fadeToggle() method toggles between the fadeIn() and fadeOut() methods. If the elements are faded out, fadeToggle() will fade them in. If the elements are faded in, fadeToggle() will fade them out. Syntax: $(selector).fadeToggle(speed,callback);

What is the syntax of jQuery fadeOut () method?

The jQuery fadeOut() method is used to fade out the element. Syntax: $(selector). fadeOut();

What is the difference between fadeOut and hide in jQuery?

Main difference between FadeIn, FadeOut vs hide, Show is When you use FadeIn and fadeout Its remove line Slowly Like Opacity will 100 to 0 in a few mili-second but On other hand hide, Show will remove the line immediately Without wasting any mili-second.

What is fadeIn in JS?

The fadeIn() method gradually changes the opacity, for selected elements, from hidden to visible (fading effect). Note: Hidden elements will not be displayed at all (no longer affects the layout of the page). Tip: This method is often used together with the fadeOut() method.


2 Answers

The problem is that there are two different types of functions in jQuery -- those that take effect immediately and those that add effects to the effects queue.

Let's take a look at your code:

container.fadeOut().delay(1000).empty().append(new_content).fadeIn();
  • fadeOut adds a fade operation to the queue
  • delay adds a delay to the queue
  • empty immediately empties the element
  • append immediately appends the content
  • fadeIn adds a fade operation to the queue

The functions that add items to the queue return immediately -- they don't wait to complete before taking effect. This means that all the functions are called at (pretty much) the same time -- they don't wait for the animation functions to complete.

You need to use the callback argument to fadeOut instead:

container.fadeOut(1000, function(){
    container.empty().append(new_content).fadeIn();
});

The function is triggered when the fade operation is complete, so the emptying and appending are delayed until the element is hidden.

like image 140
lonesomeday Avatar answered Sep 19 '22 14:09

lonesomeday


You need to use a callback function to get the effect you are looking for.

var transitionToNewContent = function(container, new_content) {
    container.fadeOut(1000, function(){
         $(this).empty().append(new_content).fadeIn();
    });
};

This ensures that the container isn't replaced until AFTER the animation is completed.

like image 39
Mark Brown Avatar answered Sep 18 '22 14:09

Mark Brown