- April 20, 2015
Scenario: While a partial page postback is occurring disable all form fields and give the user a pleasant please wait message that can be used consistently across your application. We need to create an overlay that works in conjunction with the updatepanel as well as direct from JavaScript.
Problem: Design the update progress html and css so that the entire page is overlaid with gray background. This works pretty good until scrolling on the page is involved. When the page is tall enough that the browser scrolls the overlay must by sized dynamically with each post. If you fail to do this, you will end up with odd visual with the overlay only covering a portion of the page.
The problem above is resolved in the solution described within this post. It covers the asp.net, html, css and JavaScript code to accomplish the above in re-usable fashion.
I was using the UpdatePanel control which enables you to build rich, client-centric web applications. By using the UpdatePanel controls you can refresh selected parts of the page instead of refreshing the whole page with a postback. While the partial page post back occurs an UpdateProgress control is available to provide the user with a friendly ‘please wait’ message. This all works seamlessly out of the box.
In my scenario I needed to overlay and disable all controls (make unavailable) for the user while the partial page update happens. The application allows for file uploads (which cannot participate in partial page updates). A full post back must occur for this to work correctly.
My ASPX page has the following structure with typical UpdatePanel, ContentTemplate, Triggers and UpdateProgress controls. The trigger designates that the btnSubmitAdmin will perform a full postback. I want the full postback user interaction to look similar as the partial page updates. As a result, I will be using the same updateprogress visual for both partial and full postbacks.
<body onload="fncOnLoad()">
<form id="form1" runat="server">
<asp:ScriptManager ID="Scriptmanager1" runat="server" EnablePartialRendering="true"></asp:ScriptManager>
<asp:UpdatePanel ID="updatePanel1" runat="server" UpdateMode="Conditional" >
<ContentTemplate>
<!-- Content Goes Here -->
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="btnSubmitAdmin" />
</Triggers>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="updatePanel1" DynamicLayout="true" DisplayAfter="1000">
<ProgressTemplate >
<uc1:WaitPanel ID="WaitPanel1" runat="server" />
</ProgressTemplate>
</asp:UpdateProgress>
</form>
<%@ Control Language="VB" AutoEventWireup="false" CodeFile="WaitPanel.ascx.vb" Inherits="Uc_WaitPanel" %>
<div id="OuterTableCellOverlay">
<div id="InnerTableCellOverlay">
<b>... Please Wait ...</b>
<br />
<asp:Image runat="server" ImageUrl="~/Images/indicator_waitanim.gif" />
</div>
</div>
Partial Class Uc_WaitPanel
Inherits System.Web.UI.UserControl
Protected Sub Uc_WaitPanel_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim css As New HtmlLink()
With css
.Href = ResolveClientUrl("~/Style/Wait.css")
.Attributes("rel") = "stylesheet"
.Attributes("type") = "text/css"
.Attributes("media") = "all"
End With
Page.Header.Controls.Add(css)
Dim url As String = ResolveClientUrl("~/Scripts/Wait.js")
Page.ClientScript.RegisterClientScriptInclude("wait", url)
End Sub
End Class
/* updateprogress css */
#OuterTableCellOverlay
{
background-color: white;
filter:alpha(opacity=85);
-moz-opacity:0.85;
z-index: 999;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
#InnerTableCellOverlay
{
border: 1px solid black;
padding: 10px;
background-color: #eee;
z-index: 998;
background-color: #eee;
filter:alpha(opacity=100);
position: absolute;
top: 0pt;
left: 0pt;
text-align: center;
}
<asp:Button ID="btnSubmitAdmin" runat="server" CssClass="btn" style="width:100px;"
OnClientClick="return fncValidateSubmit('Ready to Submit?');" Text="Save"
ToolTip="Save" Visible="false" />
//validate before submitting signature authority
function fncValidateSubmit(msg) {
//perform some client side validation checks here...
if (valid == true) {
var answer = confirm(msg);
if (answer) {
ShowWait('UpdateProgress1');
return answer;
}
} else {
alert(errmsg);
return false;
}
}
function ShowWait(progressControlId) {
SetWaitDimensions();
document.getElementById(progressControlId).style.display = 'block';
}
////call the following from <body onload="load()">
////required so that background blur is dimensioned correctly (with respect to scroll issues with browser)
////enable js to be called after ajax postback
function loadAjaxHandlers() {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
//will process during the initialization of the postback
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(
function() {
SetWaitDimensions();
}
)
}
The following is my complete Wait.js file which you can see sizes the overlay and positions the wait message.
////call the following from <body onload="load()">
////required so that background blur is dimensioned correctly (with respect to scroll issues with browser)
////enable js to be called after ajax postback
function loadAjaxHandlers() {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
//will process during the initialization of the postback
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(
function() {
SetWaitDimensions();
}
)
}
function ShowWait(progressControlId) {
SetWaitDimensions();
document.getElementById(progressControlId).style.display = 'block';
}
//set dimensions of blur element, positions progress box
function SetWaitDimensions() {
if (document.getElementById) {
var blur = document.getElementById('OuterTableCellOverlay');
var progress = document.getElementById('InnerTableCellOverlay');
progress.style.width = '444px';
progress.style.height = '100px';
var vp = getViewport();
var dm = getElementDimensions(document.body);
var sp = getScrollPosition();
if (vp.height > dm.height)
blur.style.height = vp.height + 'px';
else
blur.style.height = dm.height + 'px';
blur.style.width = '100%';
blur.style.top = (sp.y + ((vp.height - dm.height) / 3)) + 'px';
blur.style.left = (sp.x + ((vp.width - dm.width) / 2)) + 'px';
progress.style.top = document.documentElement.clientHeight / 3 - progress.style.height.replace('px', '') / 2 + 'px';
progress.style.left = document.body.offsetWidth / 2 - progress.style.width.replace('px', '') / 2 + 'px';
}
}
//returns view port dimensions
function getViewport() {
var v = { width: 0, height: 0 };
if (window.innerHeight) {
v.height = window.innerHeight;
v.width = window.innerWidth;
} else if (document.documentElement.clientHeight) {
v.height = document.documentElement.clientHeight;
v.width = document.documentElement.clientWidth;
} else {
v.height = document.body.clientHeight;
v.width = document.body.clientWidth;
}
return v;
}
//returns dimensions of element
function getElementDimensions(el) {
var dim = { width: 0, height: 0 };
dim.width = el.offsetWidth;
dim.height = el.offsetHeight;
return dim;
}
//returns window scroll position
function getScrollPosition() {
var pos = { x: 0, y: 0 };
pos.x = window.pageXOffset ? window.pageXOffset : document.documentElement.scrollLeft;
pos.y = window.pageYOffset ? window.pageYOffset : document.documentElement.scrollTop;
return pos;
}