Joel Rumerman's Blog

Thinking I'm better looking and wealthier than I really am.
posts - 15, comments - 29, trackbacks - 2

Emitting JavaScript to run on Startup in an Atlas Environment

I’ve been working with Atlas since the December CTP and in the past few weeks I’ve grown to really appreciate the way that it formalizes JavaScript programming and the framework it provides for extension. Creating client side behavior for server side controls is repeatable, flexible, and just an overall better experience.

However, there is one particular problem that is currently drawing my ire and it relates to how Atlas dependent JavaScript needs to be emitted to the client so that it executes correctly on startup, both from a normal page load point of view and a partial postback point of view. 

In a non-Atlas environment I use the Page.ClientScriptManager.RegisterStartupScript function to register any startup JavaScript. However, if I were to register some JavaScript code that relies upon Atlas, for instance var myLabel = new Sys.UI.Label($(‘ctrl1_lblName’));, using the normal RegisterStartupScript functionality, the browser would throw a JavaScript error as it doesn’t know what Sys.UI.Label is and it is unable to create a new object of that type. This error makes sense as there is no guarantee that the Atlas JavaScript files will be loaded by the time your startup code is executed as your startup JavaScript code is executed immediately after it is parsed by the browser. Having said that, Atlas provides a way to tie into its Application Load event, which is sort-of the equivalent of the body onload event, but occurs once all of the Atlas JavaScript files have been loaded and the Atlas runtime has been started. The way to do this is wrap your startup code in a function and then register that function as a delegate of the Application Load event. Here’s a code example.

Normal startup code …

var myLabel = new Sys.UI.Label ($(‘ctrl1_lblName’));
myLabel.initialize();

Startup code wrapped in a function and registered with the Application Load event.

function myStartupFunction () {
var myLabel = new Sys.UI.Label ($(‘ctrl1_lblName’));
myLabel.initialize();
 }
Sys.Application.load.add (myStartupFunction); // notice how myStartupFunction doesn’t have parentheses; it’s a delegate (function pointer).

This above code would be registered using the RegisterStartupScript method. Now, when the page first loads and Atlas’ runtime begins, myStartupFunction is part of the load multicast event and is executed in the order it was added to the event. This process can be repeated again and again as necessary for any startup code that relies upon Atlas.

This pattern works for JavaScript that is loaded on the initial page load or on a full page postback, but there exists a problem when using this pattern with UpdatePanels and performing a partial postback. The functionality of an UpdatePanel provides a way to render a section of a page without the user thinking a full postback is occurring. If a control or a page emits the JavaScript above and the developer wishes to have the JavaScript execute even on a partial postback page load, the above pattern won’t work because the Sys.Application.load event only fires the first time the page is loaded. It is not fired on subsequent partial loads. Currently (as of the April CTP), there is no event that fires as a load event that encompasses both the initial loading and a partial postback load. However, there is a work around and so far it is has proven reliable.

The work around relies upon the server code determining if it is partial rendering mode or not. Partial rendering mode can be determined by examining a property on the ScriptManager control, IsInPartialRenderingMode, that denotes whether the page got to the server through a partial postback, through a full postback, or through an initial page load. If it the server code is executing due to a partial postback, IsInPartialRenderingMode will be set to true, otherwise it will be set to false. If IsInPartialRenderingMode is set to false then the above code where we tie into the Sys.Application.load event is the route we want our code to take. If IsInPartialRenderingMode is set to true, we want to follow a different, very simple pattern of just registering the function as normal startup JavaScript. Here’s a code example.

// in some server side method like OnPreRender

String javaScriptFunction = @“

function myStartupFunction () {
var myLabel = new Sys.UI.Label ($(‘ctrl1_lblName’));
myLabel.initialize();
 }”

// this could should have error checking for nulls.
Page.ClientScriptManager.RegisterStartupScript (javaScriptFunction);

ScriptManager myScriptManager = ScriptManager.GetCurrent(Page);
if (myScriptManager.IsInPartialRenderingMode)
{

Page.ClientScriptManager.RegisterStartupScript (“myStartupFunction();”);
}
else
{
Page.ClientScriptManager.RegisterStartupScript (“Sys.Application.load.add (myStartupFunction);”);

}

In the above code where it tests myScriptManager.IsInPartialRenderingMode the code branches to either use the Sys.Application.load event or just emitting the function execution directly on the page. Emitting the function directly to the page (using RegisterStartupScript, which is a must!!) causes the code to be executed on parse. This time through the code won’t throw an exception as all of the Atlas JavaScript files have been loaded and the Atlas Runtime has been started.

So, there you have it. A way of executing JavaScript code that relies upon Atlas on both an initial load and a partial postback.

 

posted on Tuesday, June 20, 2006 4:40 PM