Triggering a jQuery Re-Draw After Getting Data With Ajax

395 Views Asked by At

Good day, all,

Long-time listener, first-time poster...

I have a client who has been promised a seemingly very complex bit of functionality. They want to load the contents of 3 separate pages into one, after a visitor to their site successfully logs in to their account. They want this to happen without a page refresh. Ajax is the solution. I am not, however, experienced with Ajax.

I'm having trouble figuring out how to tell when a $.get command (using jQuery's Ajax commands) has finished loading its content. My approach is to, once the login has been successful, to go and fetch the 3 separate pages, load their XHTML content into variables, and redraw the pages. Below you'll see my pseudo-code. I use "XXItemXX" to stand-in for actual paths. Each resulting page that I'm trying to pull in has a div with class "content" surrounding the data I want to retrieve. The XHTML looks like this:

<html>
    <head>
        <title>Page Name</title>
    </head>
    <body>
        <div id="header">...</div>
        <div class="content">
        .
        .
        .
        </div>
        <div id="footer">...</div>
    </body>
</html>

The jQuery code I've built follows. I'm able to get the form submitted and even get the content back from the various .get commands. The problem is, I can't seem to daisy-chain things as I normally would. I am struggling to figure out how to only fire the jQuery commands to draw the page once all 3 have been successfully retrieved. I'm afraid my biggest stumbling point is how to articulate this when searching with Google to see how others have dealt with this problem. I'm not sure exactly how to describe what I'm trying to accomplish in 10 words or less or in a fashion that will actually return the information I need.

Can anyone help with this? I'm afraid I have too little time and too much to learn.

<script type="text/javascript">
$('XXLoginFormXX').submit(function () {
    $.ajax({  
        type: $(this).attr('method'),
        url: $(this).attr('action'),
        data: $(this).serialize(),
        beforeSend: function() {
            $('<div class="loading">Loading...</div>').insertBefore('XXLoginFormXX').css('position','absolute');
        },
        success: function(data) {  
            // On successful login, draw page. 
            $('.loading').fadeOut('slow');
            var dr_editProfileXHTML, dr_accountOrderListXHTML, dr_wishListsXHTML;
            $.get('XXPathToEditProfilePageXX', function(data1){
                var dr_editProfileXHTML = $('div.content', data1);
            });
            $.get('XXPathToAccountOrderListPageXX', function(data2){
                var dr_accountOrderListXHTML = $('div.content',data2);
            });
            $.get('XXPathToWishListsPageXX', function(data3){
                var dr_wishListsXHTML = $('div.content',data3);
            });
            $('div.content').fadeOut(function(){
                $(this).html(dr_editProfileXHTML);
                $('XXEditProfileXHTMLXX').before(dr_accountOrderListXHTML);
                $('XXEditProfileXHTMLXX').before(dr_wishListsXHTML);
            }).fadeIn();
        }
    }); 
    return false;
});
</script>

Thank you very much for your time, help, and consideration.

Yours, Sylvan012

2

There are 2 best solutions below

0
On

If your problem is to wait that all 3 requests have returned, then:

  1. store the results in variables scoped a bit higher so that each of the callbacks can access them
  2. add a variable drawing in the same scope
  3. in each of the callbacks, check if all 3 variables are non-null and drawing is false
  4. if that's the case, then set drawing to true, and do the work
0
On

After working on this with people's generous help, I believe I've gotten it. All my thanks to Dave Briand who taught me about .when and .then.

Following is the pseudo-code I came up with. It seems to be working! Sure there's a lot of clean-up to do, but all three of the pages are now being pulled-in! Whoot!

What do you think of my solution?

<script type="text/javascript">
$('XXLoginFormXX').submit(function () {
    $.ajax({  
        type: $(this).attr('method'),
        url: $(this).attr('action'),
        data: $(this).serialize(),
        beforeSend: function() {
            $('<div class="loading">Loading...</div>').insertBefore('XXLoginFormXX').css('position','absolute');
        },
        success: function(data) {  
            // On successful login, draw page. 
            var Page01XHTML;
            var Page02XHTML;
            var Page03XHTML;

            $.when(
                $.get('XXPathToEditProfilePageXX', function(data1){
                    var Page02XHTML = $('div.content', data1);
                }),
                $.get('XXPathToAccountOrderListPageXX', function(data2){
                    var Page03XHTML = $('div.content',data2);
                }), 
                $.get('XXPathToWishListsPageXX', function(data3){
                    var Page01XHTML = $('div.content',data3);
                })
            ).then(function(Page02XHTML,Page03XHTML,Page01XHTML){
                $('.loading').fadeOut('slow');
                $('div.content').fadeOut(function(){
                    $(this).attr('id','MyAccount').html(' ' + Page01XHTML + Page03XHTML + Page02XHTML + ' ').parents('body').find('.content').each(function(){
                        dr_thisID = $(this).attr('id');
                        if (dr_thisID != 'MyAccount') {
                            $(this).appendTo($('div#MyAccount'));
                        }
                    }).parents('div#MyAccount').children().each(function(){
                        dr_thisClass = $(this).attr('class');
                        if (dr_thisClass != 'content') {
                            $(this).remove();
                        }
                    });
                }).fadeIn();
            });
        }
    }); 
    return false;
});
</script>