16

How can we make append wait until the previous append is complete. I am appending huge amount of data so the present append should check if the previous append is complete. I am able to do this by giving all the append's independently with some time delay. But practically according to my code I may have 'n' number of appends so I want to do this dynamically.

I tried using for or while loop but the script is getting corrupted and the browser is crashing because the next append is starting before the previous append is complete.


$('#printall1').click(function() {
$('#fourElementsonly').empty();
var cleartable = 0;
var maxlimit = 0;
var presentarraycount = 0;
$.post("/PortalUserReport/getjunkdata", null, function(response, status) {
    var report = eval(response);
    var totalRecordsCount = report.length; //6000
    var totalRecordsCountfortheLoop = totalRecordsCount;
    var arraycount = Math.ceil(totalRecordsCount / 1000);
    var reports = new Array(arraycount); // reports[6]
    for (var i = 0; i < arraycount; i++) {
        $('#fourElementsonly').append('<table border = "1" id = "Portal_User_elements' + i + '" style = " border-collapse:collapse; width:800px; margin:0px; padding:0px; border-color:black"> </table>');
    }
    reports[presentarraycount] = "";
    $.each(report, function(x) {
        if (cleartable == 0) {
            for (var i = 0; i < arraycount; i++) {
                $('#Portal_User_elements' + i).empty();
            }
            cleartable++;
        }
        if (recordnumber <= totalRecordsCountfortheLoop) {
            reports[presentarraycount] += "<tr style = \"height:20px;  border: 1px Solid Black\"> <td style = \"width:50px; text-align:center \"> " + recordnumber + " </td>   <td style = \"width:350px;\"> Name :" + report[x].FirstName + "</td> <td style = \"width:200px;\"> UserName :" + report[x].UserName + " </td> <td style = \"width:200px; \"> Company : " + report[x].Company + " </td> </tr>";
            reports[presentarraycount] += "<tr style = \"height:20px;  border: 1px Solid Black\"> <td > </td> <td> Registration Date : <label class = \"datepicker\"> " + report[x].ActiveDate + " </label> <td> User CN : " + report[x].UserCN + " </td> <td> Status: " + report[x].Status + " </td> </ td>  </tr>";
            reports[presentarraycount] += "<tr style = \"height:20px;  border: 1px Solid Black\"> <td> </td> <td> User Privilege : " + report[x].Privileges + " </td> <td> </td> </tr>";
            maxlimit++;
            if (maxlimit == 1000) {
                presentarraycount++;
                reports[presentarraycount] = "";
                maxlimit = 0;
            }
        }
        recordnumber++;
    });
    for (var i = 0; i < arraycount; i++) {
       $(this).delay(1000, function() {
            $('#Portal_User_elements' + i).append(reports[i]);
       });
    }
});

});
zx81
  • 41,100
  • 9
  • 89
  • 105
bluwater2001
  • 7,829
  • 5
  • 24
  • 21

9 Answers9

16

Unfortunately, the jQuery append() function does not include a callback. There is no way to really check for completion of it, as it supposedly happens immediately.

See Here for some info on how to use append efficiently. What it pretty much gets at is you can try to get all of your text into one variable and simply use append once.

[update] Since you have all your data in a JSON object from the get go, just do your looping through and put it all in a variable, then just append that once you're finished. [/update]

idrumgood
  • 4,904
  • 19
  • 29
12

Based on the answer from Tim Gard, I found this solution to be very elegant...

$(".selector").append(content).append(function() { /*code goes here to run*/ });
Zakk Diaz
  • 1,063
  • 10
  • 15
7

Very simple :)

Using when function.

$('<div id="appendedItem">Here</div>').appendTo("body");
$.when( $("#appendedItem").length > 0).then(function(){
    console.log( $("#appendedItem").length );
});
Karl Zillner
  • 581
  • 7
  • 16
  • 1
    Hmm, I do not think this will do what one would expect. As per the [jQuery documentation](https://api.jquery.com/jQuery.when/#jQuery-when-deferreds): "If a single argument is passed to jQuery.when() and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately. The doneCallbacks are passed the original argument. " Thus in your example, the value of `$("#appendedItem").length > 0` will be passed immediately to `then` – Jacques Nov 01 '21 at 13:25
  • Well...it's working :) but I understood your point. Maybe I was lucky with this code. – Karl Zillner Nov 02 '21 at 12:18
  • On this case, I was looking for a solution, found this question and I couldn't with the solutions that were here. So I founded this and answered here. – Karl Zillner Nov 02 '21 at 12:21
6

A clunky way...

One function (the existing function) handles all of the appends. The code that had followed the appends is wrapped in a new function "kickOffTheRestOfTheProcess".

After all of your initial appends, you add have one final append. It won't get executed until all the others.

$('body')).append("<script>kickOffTheRestOfTheProcess();</script>");

It's worked for me.

animuson
  • 53,861
  • 28
  • 137
  • 147
Tim Gard
  • 61
  • 1
  • 1
5

I can give you some hints on how to improve your code.

    for (var i = 0; i < arraycount; i++) {
        $('#fourElementsonly').append('<table border = "1" id = "Portal_User_elements' + i + '" style = " border-collapse:collapse; width:800px; margin:0px; padding:0px; border-color:black"> </table>');
    }

Can become:

   var html = '';  
   for (var i = 0; i < arraycount; i++) {
       html += '<table border = "1" id = "Portal_User_elements' + i + '" class="portalUserElements"> </table>';
    }
    $('#fourElementsonly').append(html);

You will accomplish:

  • 999 less jquery selections to '#fourElementsonly'
  • less code to be injected if you put in the class "portalUserElements" the styles:
    border-collapse:collapse; width:800px; margin:0px; padding:0px; border-color:black

This means you can also:

   for (var i = 0; i < arraycount; i++) {
        $('#Portal_User_elements' + i).empty(); 
    }

becomes (no for loop!):

   $('.portalUserElements').empty();

And:

for (var i = 0; i < arraycount; i++) {
    $('#Portal_User_elements' + i).append(reports[i]);
}

May become:

$('.portalUserElements').each(
     function(i) {
         $(this).append(reports[i]);
     }
);

Edit: these changes are suggested to improve your algorithm performance, while maintaining the full feature it provides.
You may want to compact everything inside a single string variable (including tables) and append it at the end.
See the articles that Russ Cam suggested you in one of his answers.

Alex Bagnolini
  • 21,990
  • 3
  • 41
  • 41
1

Are you appending to different elements or to a single element? If you're appending to a single element, it may be easier to concatenate all of your data and append as one chunk.

Also, where is the data from? If the data is static (non ajax) then you should be able to call

$('selector').append(data1).append(data2).append(data3);
Rowan
  • 5,597
  • 2
  • 22
  • 32
  • I am using using Ajax Post and getting all the data as a Json Object – bluwater2001 Oct 08 '09 at 20:09
  • Even thought the data is dynamic [ajax post and json object] ..if the returned data is small then we can use the above method. if the data is large.. browser will crash. – bluwater2001 Oct 08 '09 at 21:50
  • Have you had any problems with the code you posted? Because as far as I can tell, it should work as you're appending data to a different element each time. – Rowan Oct 08 '09 at 22:06
0

The below solution is working on all the browsers especially IE6. The response time in Firefox is 10 sec, but in IE6 it is 2 min 30 sec.

$('#printall1').click(function() {
    $('#fourElementsonly').empty();
    var cleartable = 0;
    var maxlimit = 0;
    var presentarraycount = 0;

    $.post("/PortalUserReport/getjunkdata", null, function(response, status) {
        var report = eval(response);// we have 6000 records in the report now
        var totalRecordsCount = report.length; // count = 6000 
        var totalRecordsCountfortheLoop = totalRecordsCount;
        var arraycount = Math.ceil(totalRecordsCount / 1000);
        var reports = new Array(arraycount); // reports[6]
        for (var i = 0; i < arraycount; i++) {
            $('#fourElementsonly').append('<table border = "1" id = "Portal_User_elements' + i + '" style = " border-collapse:collapse; width:800px; margin:0px; padding:0px; border-color:black"> </table>');
        }
        reports[presentarraycount] = "";
        $.each(report, function(x) {
            if (cleartable == 0) {
                for (var i = 0; i < arraycount; i++) {
                    $('#Portal_User_elements' + i).empty(); 
                }
                cleartable++;
            }

            if (recordnumber <= totalRecordsCountfortheLoop) {
                reports[presentarraycount] += "<tr style = \"height:20px;  border: 1px Solid Black\"> <td style = \"width:50px; text-align:center \"> " + recordnumber + " </td>   <td style = \"width:350px;\"> Name :" + report[x].FirstName + "</td> <td style = \"width:200px;\"> UserName :" + report[x].UserName + " </td> <td style = \"width:200px; \"> Company : " + report[x].Company + " </td> </tr>";
                reports[presentarraycount] += "<tr style = \"height:20px;  border: 1px Solid Black\"> <td > </td> <td> Registration Date : <label class = \"datepicker\"> " + report[x].ActiveDate + " </label> <td> User CN : " + report[x].UserCN + " </td> <td> Status: " + report[x].Status + " </td> </ td>  </tr>";
                reports[presentarraycount] += "<tr style = \"height:20px;  border: 1px Solid Black\"> <td> </td> <td> User Privilege : " + report[x].Privileges + " </td> <td> </td> </tr>";
                maxlimit++;
                if (maxlimit == 1000) {
                    presentarraycount++;
                    reports[presentarraycount] = "";
                    maxlimit = 0;
                }
            }
            recordnumber++;
        });

        for (var i = 0; i < arraycount; i++) {
            $('#Portal_User_elements' + i).append(reports[i]);
        }
    });
});
Spooky
  • 2,966
  • 8
  • 27
  • 41
bluwater2001
  • 7,829
  • 5
  • 24
  • 21
  • 3
    it looks like your appending each element in the report array individually. This will be **SLOW** in all browsers, especially IE6. Take a look at the article posted in this answer http://stackoverflow.com/questions/1539841/wait-untill-previous-append-is-complete-jquery/1539888#1539888 . You might also want to take a look at documentFragments - http://ejohn.org/blog/dom-documentfragments/ – Russ Cam Oct 08 '09 at 22:16
0

building on the guys answers above i did this in angular:

el.append('<span>random stuff</span>').append('{{randomFunction()}}');
Post Impatica
  • 14,999
  • 9
  • 67
  • 78
0

Perhaps another way might have been to simply check whether the length of the innerHTML of the container you're appending to equals the length of the last chunk of content, within your polling function.

If not dont append, if so append.

rism
  • 11,932
  • 16
  • 76
  • 116