2

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

Sylvan012
  • 21
  • 3
  • 1
    you seem to know how to code so i'll just post this as a comment - have you looked at ajax when() and done()? http://api.jquery.com/jquery.when/ – Dave Briand Jun 27 '14 at 12:53
  • It appears that you are able to get the content and to successfully call inject your content into the dom after your AJAX call has completed, but you are having difficulty waiting for all of them to finish downloading before showing them all to the user correct? If that's the case, I would handle that in one of two ways: either go ahead and fill all 3 containers and hide them by default. when your ajax calls complete, have them also check the contents of the other 2 containers. if they are all populated with data, then do a $.show(); to show the hidden containers – Andrew Tran Jun 27 '14 at 12:55
  • Andrew - I'm not sure how to tell when all of the 3 .get commands have finished. – Sylvan012 Jun 27 '14 at 12:58
  • Dave is on the right track here. You can either use jQuery.when() or build your own ajax queue manager. [This questions](http://stackoverflow.com/questions/4785724/queue-ajax-requests-using-jquery-queue) first answer has a good starting point to build your own. – s1lv3r Jun 27 '14 at 12:59
  • In looking at the documentation for jQuery.when(), I'm afraid I run into another block. I do not really understand what a "Callback" function is. Nor do I know how to apply .when to three Ajax functions. Do you have any insight into a "For Dummies"-like description of this so I can research, further? – Sylvan012 Jun 27 '14 at 13:16
  • Oh, wait a sec... Think I've got something here...! One sec while I try a few things... – Sylvan012 Jun 27 '14 at 13:24
  • Dave Briand - THANK YOU! Learning about .when() and .then() helped incredibly! With this knowledge I was able to come up with a fairly effective solution. You were a great help! I've posted my solution pseudo-code, below, for people to see. – Sylvan012 Jun 27 '14 at 15:27

2 Answers2

0

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
jcaron
  • 17,302
  • 6
  • 32
  • 46
0

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>
Sylvan012
  • 21
  • 3