Question

We are putting together an FSSO API that requires a popup window for the user to log in. In the popup, we perform two tasks:

  1. Calling a service to populate a profile values, then setting a page to redirect the user to based on the event type (login or registration).

  2. Redirecting the user to the redirect page in the parent window and closing the FSSO popup.

Code:

$(document).ready(function() {
            var nextPage = "index.html",
            storage = window.opener.sessionStorage;

            function setStorage(callback){
                $.ajax({
                    type: "GET",
                    cache: false,
                    dataType: "json",
                    url: "https://someserviceURL/service/profile",
                    success: function(objJSON){
                        //storage.op is set on the parent page when login or reg link is clicked
                        if (storage.op == "login") {
                            storage.firstname = objJSON.firstName;
                            storage.lastname = objJSON.lastName;
                            storage.setItem('loggedIn',JSON.stringify(true));   //Some browsers don't support booleans in sessionStorage
                            nextPage = "dashboard.html";
                        }
                        else if (storage.op == "register") {
                            storage.firstname = objJSON.firstName;
                            storage.lastname = objJSON.lastName;
                            storage.setItem('loggedIn',JSON.stringify(true));
                            nextPage = "options.html";
                        }
                    },
                    error: function( jqXHR,  textStatus,  errorThrown){
                        //display error message
                    }
                });

                callback();
            }

            setStorage(function(){
                if (typeof window.opener != "undefined" && window.opener != null){
                    setTimeout(function(){
                        window.opener.location.href = nextPage;
                        window.close();
                    },3000);
                }
            });

        });

Problem: The window seems to be closing before I'm able to set the sessionStorage values if I set the timeout to anything less than 3000. I just want to close the window in response to those values being set, not some arbitrary amount of time passing. I tried the trick of setting the timeout to 0 but no luck, and I tried just the callback with no timeout.

Looking for best practices here on handling timing issues like these, what I have now feels hacky. :)

Was it helpful?

Solution

The call to $.ajax() is asynchronous, which means that the rest of the script will continue to execute immediately after the call is made, without waiting for the call to complete and trigger the success or error handlers.

This means that your function called callback is being executed before your success handler. It may usually work as intended with a 3000ms timeout as your web service often takes less time than this to complete, so your callbacks are executed first in these cases. As you mentioned, this is not a reliable way to control the order of events.

One solution would be to execute your callback as part of the complete handler, as follows:

$(document).ready(function() {
        var nextPage = "index.html",
        storage = window.opener.sessionStorage;

        function setStorage(callback){
            $.ajax({
                type: "GET",
                cache: false,
                dataType: "json",
                url: "https://someserviceURL/service/profile",
                success: function(objJSON){
                    //storage.op is set on the parent page when login or reg link is clicked
                    if (storage.op == "login") {
                        storage.firstname = objJSON.firstName;
                        storage.lastname = objJSON.lastName;
                        storage.setItem('loggedIn',JSON.stringify(true));   //Some browsers don't support booleans in sessionStorage
                        nextPage = "dashboard.html";
                    }
                    else if (storage.op == "register") {
                        storage.firstname = objJSON.firstName;
                        storage.lastname = objJSON.lastName;
                        storage.setItem('loggedIn',JSON.stringify(true));
                        nextPage = "options.html";
                    }
                },
                error: function( jqXHR,  textStatus,  errorThrown){
                    //display error message
                },
                complete: function( jqXHR,  textStatus){
                    callback();
                }
            });
        }

        setStorage(function(){
            if (typeof window.opener != "undefined" && window.opener != null){
                    window.opener.location.href = nextPage;
                    window.close();
            }
        });
    });

Or if you don't care about the returned arguments you could pass callback directly to complete. Note that complete will be executed in both success and error conditions, so you might want to call callback only in your success handler and do something else with any errors.

OTHER TIPS

You should call your callback as the last action of your success function:

.
.
.
else if (storage.op == "register") {
   storage.firstname = objJSON.firstName;
   storage.lastname = objJSON.lastName;
   storage.setItem('loggedIn',JSON.stringify(true));
   nextPage = "options.html";
 }

 callback();  // execute your callback to the window closer here.

},
error: function( jqXHR,  textStatus,  errorThrown){
      //display error message
                }
      });
      }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top