eoto
eoto

Reputation: 63

jQuery when().then() show loading during AJAX call

I'm working on a web app on CodeIgniter with jQuery and I'm trying to make a javascript function to show an ajax loading image during ajax calls. In my example, the ajax call is successful but the loading never show so I think the problem is the first function in "when" is not executed. Does someone could help me with this? Thanks

http://jsfiddle.net/fEnPz/8/

HTML

<div id="form"></div>​

CSS

#form {
  height: 300px;
  width: 350px;
}

.loadingOverlay {
  border: 1px solid #EFEFEF;
  background-color: #D8DCDF;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
  position: absolute;
  padding: 10px;
  z-index: 1;
  -moz-opacity: 0.50;
  opacity: 0.50;
  -ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=50);
}​

Javascript

function displayLoading(Container, Callback) {
    var height = Container.height();
    var width = Container.width();
    $.when(function() {
      Container.append('<div class="loadingOverlay" style="width: '+ width +'px; height: '+ height +'px;"><img class="ajaxLoading" src="http://www.ajaxload.info/images/exemples/2.gif" /></div>');
      Container.find(".loadingOverlay").position({
          "my": "center center",
          "at": "center center",
          "of": Container
      });
      Container.find(".ajaxLoading").position({
          "my": "center center",
          "at": "center center",
          "of": Container
      });
    }, Callback()).then(function() {
      Container.find(".loadingOverlay").hide().remove();
    });
}

displayLoading($("#form"), function() {
    $.ajax({
      url: 'http://search.twitter.com/search.json',
      dataType: 'jsonp',
      data: {
            q: 'ConceptionAb6'
      },
      success: function(results) {
        // Only for testing the loading
        setTimeout(function() {
          alert(results.max_id);
        }, 2000);
      },
      error: function() {
        alert("error!");
      }
    });
});

Upvotes: 2

Views: 7937

Answers (4)

tim
tim

Reputation: 3903

For the purposes of making an ajax loading animation, just do this:

$("<img src='loading.gif'/>").bind({
    ajaxStart: function() { $(this).show(); },
    ajaxStop: function() { $(this).hide(); }
});

It utilizes jQuery's built-in global ajax events that fire anytime an $.ajax() call happens and binds them to your animation element.

Upvotes: 2

Beetroot-Beetroot
Beetroot-Beetroot

Reputation: 18078

Stripping displayLoading() right down to the bones I get ...

function displayLoading(Container, Callback) {
    ...
    $.when(function(){...}, Callback()).then(function() {
        ...
    });
}

... revealing that $.when() is not being used correctly.

$.when() expects all its arguments to be promises, which not the case for either argument.

  • First argument: a function that's never called.
  • Second argument: a function that is called but which doesn't return a promise.

Moreover, $.when() is unnecessary as only one promise (the jqXHR returned by $.ajax()) is involved.

I think the pattern you want is something like this :

function displayLoading(container, promise) {
    //create a spinner in container if not already created
    //show spinner
    //hide other content
    promise.done(function() {
        //hide spinner
        //show other content
    });
}

displayLoading($("#form"), $.ajax({
    //ajax options
});

Upvotes: 1

Marcio Junior
Marcio Junior

Reputation: 19128

In my opinion $.when is more usual when using several async requests. In your case I would use:

$.ajax({
    beforeSend: function() {
        var Container = $("#form");
        var height = Container.height();
        var width = Container.width();
        Container.append('<div class="loadingOverlay" style="width: '+ width +'px; height: '+ height +'px;"><img class="ajaxLoading" src="/img/ajax-loader.gif" /></div>');
        Container.find(".loadingOverlay").position({
            "my": "center center",
            "at": "center center",
            "of": Container
        });
        Container.find(".ajaxLoading").position({
            "my": "center center",
            "at": "center center",
            "of": Container
        });
    },
    url: 'http://search.twitter.com/search.json',
    dataType: 'jsonp',
    data: {
        q: 'ConceptionAb6'
    },
    success: function(results) {
        alert(results.max_id);
    },
    error: function() {
        alert("error!");
    },
    complete: function() {
        $("#form").find(".loadingOverlay").hide().remove();
    }
});
​

Upvotes: 1

David Fells
David Fells

Reputation: 6798

The problem seems to be having the ajax call wrapped in a function. This works fine:

function displayLoading(Container, Callback) {
    var height = Container.height();
    var width = Container.width();

      Container.append('<div class="loadingOverlay" style="width: '+ width +'px; height: '+ height +'px;"><img class="ajaxLoading" src="/img/ajax-loader.gif" /></div>');
      Container.find(".loadingOverlay").position({
          "my": "center center",
          "at": "center center",
          "of": Container
      });
      Container.find(".ajaxLoading").position({
          "my": "center center",
          "at": "center center",
          "of": Container
      });

    $.when($.ajax({
      url: 'http://search.twitter.com/search.json',
      dataType: 'jsonp',
      data: {
            q: 'ConceptionAb6'
      },
      success: function(results) {
        setTimeout(function() {
          alert(results.max_id);
        }, 2000);
      },
      error: function() {
        alert("error!");
      }
    })).then(function() {
      Container.find(".loadingOverlay").hide().remove();
    });
}

displayLoading($("#form"));
​

I'd read up on how deferred objects work in jQuery and figure out a different approach. http://colonelpanic.net/2011/11/jquery-deferred-objects/

Upvotes: 1

Related Questions