4

I'm trying to display two progress bars for multiple ajax requests. One progress bar reaches 100% each time one of my 18 ajax requests is complete and another reaches 100% when all 18 requests are complete. The first bar works great and is implemented in my ajax success callback. I'm having trouble triggering my second bar because it seems I need a second success callback...

Here is the code for my first ajax requests. It gets called 18 times because that is how many items are in my Config object.

for (var propt in Config) {

    var db = '...';
    var user = '...';
    var pword = '...';
    var func = '...';
    var dat = {"...": propt };
    var url = "https://...";

    var callData = jQuery.extend({"Db": db, "User": user, "Password": pword, "Function": func}, dat);

    $.ajax({
        type: "POST",
        url: url,
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(callData),
        xhr: function() {
            var xhr = new window.XMLHttpRequest();
            //Download progress
            xhr.addEventListener("progress", function(event){
                    var percentComplete = (event.loaded / event.total)*100;
                    //Do something with download progress
                            tableProgressBar(percentComplete);
            }, false);
            return xhr;
        },
        success: successHandlerRunTest1,
        error: errorHandlerRunTest1,
        dataType: "json"
    });
    $('#jsonMsg1').html('Running...');
    $('#jsonRslt1').html(' ');
}

I would also like to fire this success function simultaneously.

success : function (serverResponse) {
    response[response.length] = serverResponse;
    $('#progress-bar').text(current + ' of ' + total + ' tables are done');
    current++;
},

Unfortunately I don't believe I can call the second success function from within the first success function because the first receives special parameters containing JSON data.

I've tried something like...

success : function (serverResponse) {
    response[response.length] = serverResponse;
    $('#progress-bar').text(current + ' of ' + total + ' tables are done');
    current++;

    successHandlerRunTest1(data);
},

...but this doesn't work because the "data" object that my successHandlerRunTest1(data) receives is empty.

Is there a way to perform two success callbacks per ajax request?

Aaron Turecki
  • 345
  • 3
  • 7
  • 24

3 Answers3

7

Don't use the success parameter.

Use the done method to attach callbacks, as it returns the promise for chaining you can call it multiple times:

$.ajax({
    type: "POST",
    url: url,
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify(callData),
    xhr: function() {
        var xhr = new window.XMLHttpRequest();
        xhr.addEventListener("progress", function(event){
            var percentComplete = (event.loaded / event.total)*100;
            tableProgressBar(percentComplete);
        }, false);
        return xhr;
    },
    dataType: "json"
})
.done(successHandlerRunTest1)
.fail(errorHandlerRunTest1)
.done(function (serverResponse) {
    response[response.length] = serverResponse;
    $('#progress-bar').text(current + ' of ' + total + ' tables are done');
    current++;
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Could also utilize `deferred.progress` within `.then()` pattern, i.e.g., `.then(fn /* done */, fn /* fail */, fn /* progress */)` ? Thanks – guest271314 Jul 29 '14 at 23:24
  • [Yes, that seems to be possible](http://stackoverflow.com/a/19639961/1048572) (and indeed favourable over mixing the callback into the listener setup) – Bergi Jul 29 '14 at 23:27
  • Interesting. Appear that `jQuery.ajax()` `jqxhr` (`deferred`) object not possess `notify` property , callback ? though `progress` callback present ; neither documented at http://api.jquery.com/jQuery.ajax ? see notify status mentioned at recent comments http://stackoverflow.com/questions/24971676/notify-after-async-task-is-done#comment38819796_24973026 . Any illumination as to why progress part of ajax jqxhr ? not appear to include corresponding `.notify` , documentation ? piece attempts sync pattern of `.notify` , `progress`, `jqxhr` http://jsfiddle.net/guest271314/N6EgU Thanks – guest271314 Jul 30 '14 at 02:57
  • Both are [documented for deferreds](http://api.jquery.com/category/deferred-object/). jQxhr objects are promises, not deferreds, they don't have `resolve` or `reject` methods either. It's not mentioned in the $.ajax docs because progress notifications are not used by it, as you know it doesn't even support XHR2. – Bergi Jul 30 '14 at 08:28
  • Thank you, this was a big help and worked perfectly. – Aaron Turecki Jul 30 '14 at 17:59
2

You could simply pass both callbacks inside the original success callback. Then use .apply to pass the same arguments as the success callback was originally called with.

success: function()
{
    callbackOne.apply(this, arguments);
    callbackTwo.apply(this, arguments);
}

see .apply() method.

see arguments property.

Also as a side note never ever put database usernames and passwords in javascript. Since anybody can access it.

Kyle Needham
  • 3,379
  • 2
  • 24
  • 38
1

Try (this pattern) , utilizing deferred.always()

html

<progress id="p1" max="1" value="0"></progress>
<progress id="p2" max="17" value="0"></progress>
<span id="jsonMsg1"></span>
<span id="progress-bar"></span>

js

$(function () {
    var count = null;
    var Config = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
    for (var propt in Config) {

        var db = '...';
        var user = '...';
        var pword = '...';
        var func = '...';
        var dat = {
            "...": propt
        };
        var url = "/echo/json/";

        var callData = jQuery.extend({
            "Db": db,
            "User": user,
            "Password": pword,
            "Function": func
        }, dat);
        var successHandlerRunTest1 = function (data, textStatus, jqxhr) {
            // Do something with download progress
            $("#p1").val(1);
        };
        var response = [];
        $.ajax({
            type: "POST",
            url: url,
            contentType: "application/json; charset=utf-8",
            data: {
                json: JSON.stringify(callData)
            },
            beforeSend: function (jqxhr, setiings) {
                jqxhr.count = ++count;
                // Do something with download progress
                $("#p1").val(0);
            },
            /*
        xhr: function() {
            var xhr = new window.XMLHttpRequest();
            //Download progress
            xhr.addEventListener("progress", function(event){
                    var percentComplete = (event.loaded / event.total)*100;
                    //Do something with download progress
                            tableProgressBar(percentComplete);
            }, false);
            return xhr;
        },
        */
            success: successHandlerRunTest1,
            error: function (jqxhr, textStatus, errorThrown) {
                console.log(errorThrown)
            },
            dataType: "json"
        })
            .always(function (data, textStatus, jqxhr) {

            $('#jsonMsg1').html('Running...');
            response[response.length] = data;
            $("#progress-bar")
                .text(Number(data["..."]) 
                + ' of ' 
                + Config.length + ' tables are done');
            $("#p2").val(Number(data["..."]));
            // Do something with download progress
            if (data["..."] === "17" && jqxhr.count === 18) {

                console.log(data["..."]);
                $('#jsonMsg1').html('Done...');
                $("#progress-bar")
                    .text(Number(data["..."]) + 1 
                    + ' of ' 
                    + Config.length + ' tables are done');

            };
        });
        // $('#jsonRslt1').html(' ');
    };
});

jsfiddle http://jsfiddle.net/guest271314/z6DzF/4/

See

http://api.jquery.com/jQuery.ajax/#jqXHR

http://api.jquery.com/deferred.always/

guest271314
  • 1
  • 15
  • 104
  • 177