views:

5399

answers:

7

Hey all,

I have an application that I am writing that modifies data on a cached object in the server. The modifications are performed through an ajax call that basically updates properties of that object. When the user is done working, I have a basic 'Save Changes' button that allows them to Save the data and flush the cached object.

In order to protect the user, I want to warn them if the try to navigate away from the page when modifications have been made to the server object if they have not saved. So, I created a web service method called IsInitialized that will return true or false based on whether or not changes have been saved. If they have not been saved, I want to prompt the user and give them a chance to cancel their navigation request.

Here's my problem - although I have the calls working correctly, I can't seem to get the ajax success call to set the variable value on its callback function. Here's the code I have now.

   ////Catches the users to keep them from navigation off the page w/o saved changes...
window.onbeforeunload = CheckSaveStatus;
var IsInitialized;

function CheckSaveStatus() {

    var temp = $.ajax({
     type: "POST",
     url: "URL.asmx/CheckIfInstanceIsInitilized",
     data: "{}",
     contentType: "application/json; charset=utf-8",
     dataType: "json",
     success: function(result) {
      IsInitialized = result.d;
     },
     error: function(xmlHttpRequest, status, err) {
      alert(xmlHttpRequest.statusText + " " + xmlHttpRequest.status + " : " + xmlHttpRequest.responseText);
     }

    });

    if (IsInitialized) {
     return "You currently have unprocessed changes for this Simulation.";
    }
}

I feel that I might be trying to use the Success callback in an inappropriate manner. How do I set a javascript variable on the Success callback so that I can decide whether or not the user should be prompted w/ the unsaved changes message?

As was just pointed out, I am making an asynchronous call, which means the rest of the code gets called before my method returns. Is there a way to use that ajax call, but still catch the window.onunload event? (without making synchronos ajax)

+2  A: 

The thing is that the request to Ajax call is asynchronous. So by the time you are checking you IsInitialized the call has not finished yet.

I suggest specifying your behaviour in the success function.

Basically having synchronous calls with ajax is if not impossible than really discouraged.

Rashack
Any suggestions on how I can still catch that window.onbeforeunload event using the asynchronous call?
Nathan
+6  A: 

Since you need this behavior in the unload event, you will have to make a synchronous call instead. However it may freeze the browser window/tab dependent on how long the call will take, but because you're effectively trying to prevent the user from closing the window...

Add async: false to your JSON to make a synchronous call.

Pawel Krakowiak
+1  A: 

You could theoretically kill the event (return false) and close the window on success, but I think you would run into Javascript restrictions set by some users, and also just confuse them as to why their window isn't closing. So, I agree with Pawel Krakowiak, the ajax call itself must be synchronous.

I'll add that you'll want to give the user some notification that you are checking on status (not a popup, please. one of those nice notification banners at the top of the window) and be sure to set the $.ajax "timeout" option to something more reasonable for this situation, so they aren't waiting forever for the window to close.

Jerph
+1, agreed on the notification. Good point.
Pawel Krakowiak
A: 

Looks like the best approach for me was to use the async: false option on my ajax call. Although I understand Rashack's hesitation for doing this, I think that this situation justifies the means.

Also great point by Jerph about making sure that I don't leave the user hanging while I am trying to verify their status. That coupled w/ the timeout option is important.

Thanks to everyone who commented.

Nathan
A: 

This still didn't answer the question how to access the variable!

A: 

I had a similar problem with attempting to set a property for a data object through the success callback of an ajax request. Using async: false didn't solve my issue, either. What I ended up doing was to use a setTimeout call outside the ajax call, and set the timeout value to 1, like so:

function getSessionid() {
$.ajax({
type: 'POST',
url: 'getSession.php',
dataType: 'text',
success: function(result){myData.sessionid = result;},
error: function(data) {alert("Error!\n" + data);} });
setTimeout(function() {alert('sessionid = ' + myData.sessionid);},1);
}

Just having that 1 millisecond delay made all the difference in the world. Without it, the sessionid property wouldn't set outside the ajax call, though alerts within the callback showed that it was, indeed, being set. It's something to think about, should you come up against a similar problem.

GeekCaveCreations