Last week, I was working with a client on an ASP.NET page that dynamically creates controls on the page. The usual conversation in this endeavor is how to create the controls in such a way that they participate in ViewState and form value restoration (simple answer – recreate the controls every time in page_load or page_init and the rest happens magically). But, this leads to another problem.
Let’s say that the web page is for editing data in a database and that the database will not be updated until the server presses the SAVE button. After several roundtrips to the server during editing and dynamically creating new controls, there will be some data on the page that would be lost if the user does a refresh (like doing a F5 in IE). When a refresh is sent from IE, ASP.NET sees this as a new request and the page will probably display the current state of the data in the database and therefore loses the differences of the previous screen (if you’re doing stateless programming). So, how can we protect the user out here? The answer is: you can’t, but you can warn them of what is happening.
In my research of this issue, I found that Dino has a great MSDN article that shows how to build a HTTP Module (inherits from IHttpModule) that detects a page refresh. This allows the developer to protect from operations that one would not want repeated (like deleting a customer’s order). But that does not address this issue.
Fortunately, JavaScript has an event that fires right before the onUnload event called onBeforeUnload. This event has the benefit of allowing someone to cancel the leaving of the page. A good description of this is located at http://www.webreference.com/dhtml/diner/beforeunload/index.html. Basically, when a function is registered for this event, the user gets a message prompting for leaving the page and the message is programmatically controlled.
Due to lessons learned from our Atomic class, we add the following to the Pre_Render event in our PageTemplate class () when we want to enable this functionality:
If Me._EnableBeforeOnLoad Then
sb.Append("function unloadMess() {" & Environment.NewLine)
sb.Append(" return ""You will lose any edit's since last Update"";")
sb.Append("}" & Environment.NewLine)
sb.Append("function setBunload(on){" & Environment.NewLine)
sb.Append(" window.onbeforeunload = (on) ? unloadMess : null;" & Environment.NewLine)
sb.Append("}" & Environment.NewLine)
EndIf
This logic exists within a set of other JavaScript related functionality that our custom page class would do – like setting focus, title, and other JavaScript functions (so don’t forget the SCRIPT tags).
Another thing that you’ll want to do with this technique is to have certain buttons disable the event. For example, the button that saves the data should not warn the user that they could possibly lose data. So, do the following for buttons that operate on the page:
Button1.Attributes("OnClick") = "setBunload(false);"
Note: this functionality is tied into the JavaScript functions defined in the pre_render event.
So, that’s it. The other benefit here is that other activities that would lose changes are caught as well (for example, clicking on menu links, closing the browser, typing in a new URL, clicking on the favorites list, etc).