The AJAX client library is made up of three main logical
Figure 2-1:
A graphical view of the AJAX client library
As mentioned in the previous sections, JavaScript extensions add new methods and capabilities to native JavaScript objects and enable registration
The core framework classes form a
In the remainder of this chapter, we’ll take a look at the main functionality implemented in the Microsoft AJAX library, starting with the Application object.
The execution of each ASP.NET AJAX page is controlled by an application object that is
Whenever an ASP.NET AJAX page is loaded in the browser, an instance of the Sys._Application class is promptly created and assigned to the Sys.Application object:
Sys.Application = new Sys._Application();
In addition, each ASP.NET AJAX page is injected with the following script code:
<script type="text/javascript"> <!-- Sys.Application.initialize(); // --> </script>
This code is placed immediately after the closing tag of the page’s form, and it commands the loading of any script files registered for loading with the page’s script manager. More details on script loading are unveiled in Chapter 3, “The Pulsing Heart of ASP.NET AJAX.” As a result, the
Sys.Application
object is the
The Sys._Application class derives from Component and is the entry point in the page hierarchy to locate client-side components either bound to server controls or programmatically added to the application. Table 2-3 lists some of the methods available on the Sys._Application class.
|
Member |
Description |
|---|---|
|
addComponent |
Adds the specified Microsoft AJAX library component to the page hierarchy |
|
beginCreateComponents |
Starts adding new Microsoft AJAX library components to the page |
|
endCreateComponents |
Ends adding new Microsoft AJAX library components to the page |
|
findComponent |
Looks up the specified Microsoft AJAX library component in the page |
|
getComponents |
Gets the list of Microsoft AJAX library components found in the page |
|
initialize |
Ensures that all referenced script files are loaded |
|
notifyScriptLoaded |
Called by script files to notify the application object that the script has been successfully loaded |
|
queueScriptReference |
Queues a new script reference for loading |
|
removeComponent |
|
The application object serves two main purposes: providing access to page components, and loading external script files registered with the page script manager. Note that each external script file registered with the script manager needs to place a notifyScriptLoaded call at the bottom of its source to notify the application of success.
The
findComponent
method
Sys._Application.findComponent(id); Sys._Application.findComponent(id, parent);
The former overload takes the ID of the component and uses it to look up and navigate the hierarchy all the way down from the root. When a non-null
parent
argument is specified, the search is restricted to the
Microsoft Client library also supports a shortcut for retrieving runtime components-the $find method. The $find method is an alias for findComponent .
var $find = Sys.Application.findComponent;
You can use this method to locate all components created by server controls and extenders, as well as by your own JavaScript code and, if supported, by XML-Script declarations.
Table 2-4 lists the events
|
Event |
Description |
|---|---|
|
Init |
Occurs when the page is first
|
|
Load |
Occurs when the page is loaded |
|
loadTimedOut |
Occurs when the loading step takes too much time to complete |
|
scriptLoadFailed |
Occurs when one script fails to load for whatever reason |
|
Unload |
Occurs when the page is unloaded |
When an ASP.NET AJAX page first loads up, the load event is fired for the client code to perform any required initialization. Note that the event refers to the page lifetime, not the application lifetime. So whenever a classic postback occurs, you receive a new load event. You don’t receive events for any AJAX-style postback. Likewise, the unload event is fired when the page is unloaded.
The load event occurs after an ASP.NET AJAX page has been loaded and initialized completely. For such a page, the load event is preferable to the browser’s onload for initialization purposes. Only when you get the Microsoft AJAX library load event, therefore, can you be sure that the page is ready for user interaction.
The
unload
event occurs just before the Microsoft AJAX library runtime releases the page and all of its resources. For the sake of the application’s stability, you should use this event instead of the browser’s
onunload
event for clean-up
The following code shows how to add handlers to the load and unload events via script:
Sys.Application.add_load(_pageLoadHandler); Sys.Application.add_unload(_pageUnloadHandler);
You add this code to a <script> tag you import in the page. Note that this <script> tag must be placed past the definition of the script manager control, as shown here:
<form id="Main" runat="server"> <asp:ScriptManagerrunat ="server" ID="scriptManager" /> <script type="text/JavaScript" language="JavaScript"> Sys.Application.add_load(_pageLoadHandler); Sys.Application.add_unload(_pageUnloadHandler); </script> ... </form>
An even easier way to define load and unload handlers is by means of predefined function names: pageLoad and pageUnload . These functions need to be global and parameterless.
<script type="text/JavaScript" language="JavaScript"> function pageLoad() { alert("Being loaded"); } function pageUnload() { alert("Being unloaded"); } </script>
Because this piece doesn’t directly call into any of the Microsoft AJAX library objects-including Sys.Application -you can safely place it everywhere, even at the top of the ASP.NET AJAX page.
Generally, the
In the Microsoft AJAX library, the root component class is Sys.Component . The root class for controls is named Control and, guess what, lives in the Sys.UI namespace. In the Microsoft AJAX library, Sys.UI.Control derives from Sys.Component . Let’s learn more about the common properties of components; we’ll work with controls later in the chapter.
Derived from the JavaScript native type Object , the Sys.Component class defines a number of properties and events shared by all components. Table 2-5 lists the properties of the Sys.Component class.
|
Property |
Description |
|---|---|
|
events |
Lists all events fired by the class |
|
id |
Gets and sets the ID used to identify the component |
|
isInitialized |
Indicates whether the component has been initialized |
|
isUpdating |
Indicates whether the component is in the middle of a batch update operation |
The Sys.Component class features an initialize method that is used to start up the component. The base implementation of the method simply sets an internal flag to denote that the component has been initialized. Derived classes can further specialize the method to accomplish additional tasks. Table 2-6 lists the methods of the Sys.Component class.
|
Method |
Description |
|---|---|
|
beginUpdate |
Starts a batch operation aimed at updating the state of the component |
|
dispose |
Disposes of all resources associated with the class |
|
endUpdate |
Signals that an update operation has
|
|
initialize |
Performs any task required to initialize the component |
|
raisePropertyChanged |
Raises the propertyChanged event. |
In addition to the members
The
Sys.Component
class features a built-in mechanism to detect ongoing changes to the properties of a component. When this happens, the
propertyChanged
event is fired. The method
raisePropertyChanged
on the base class allows derived components to fire the
propertyChanged
event to notify
this.set_MyProperty = function(value) { _myProperty = value; this.raisePropertyChanged("MyProperty"); }
Generally, derived components place a call to raisePropertyChanged in the set method of a given property. For a derived component, using the property changes mechanism is optional and not mandatory.
The
Sys.Component
class also provides facilities when too many properties are going to be updated at the same time. To minimize screen updates, you can tell the object to perform property updates in a batch. To do so, you
Depending on the specific component, batch updates can improve performance and minimize screen updates.
The
$create
alias provides a
var $create = Sys.Component.create = function Sys$Component$create( type, properties, events, references, element) { ... }
Of all the arguments just shown, only the
type
argument is mandatory; all others are optional. For example, the following code creates an instance of
Samples.UI.Button
and
$create(Samples.UI.Button, {}, {'click':'button1_Click'}, {} $get('sendDataButton') );
The $create method defines the type to create, a list of properties, event handlers, and even an optional DOM element if any exists. The $create alias can also handle scenarios in which components have references to other components. In addition, objects are automatically registered with Sys.Application , thus allowing components to be found through $find .
The Sys.Component class implements two interfaces that revolve around the disposal of any component instance: the Sys.IDisposable and Sys.INotifyDisposing interfaces. The Sys.Dispos able interface features the dispose method; the Sys.INotifyDisposing interface lists the sole disposing event.
Components are required to be disposable so that you can free all of their client resources when used in the context of updatable panels. In addition, you should make sure the dispose method handles being called more than once. Here’s an example:
dispose: function() { // Check whether childObject1 has been disposed of if (!_childObject1_disposed) { ... } }
In this case, the
_childObject1_disposed
member is an internal member of the particular component that tracks whether or not the present component has gotten rid of its child objects and resources, including handlers. It is recommended that you use internal flags to check whether any child components (for example, event handlers) being manually disposed have already been disposed of when the whole component is
AJAX libraries in general, and ASP.NET AJAX Extensions in particular, owe their growing popularity to their ability to execute out-of-
In the Microsoft AJAX library, a remote request is represented by an instance of the Sys.Net.WebRequest class. Table 2-7 lists the properties of the class.
|
Property |
Description |
|---|---|
|
body |
Gets and sets the body of the request |
|
executor |
Gets and sets the Microsoft Client library object that will take care of executing the request |
|
headers |
Gets the headers of the request |
|
httpVerb |
Gets and sets the HTTP verb for the request |
|
timeout |
Gets and sets the timeout, if any, for the request |
|
url |
Gets and sets the URL of the request |
The WebRequest class defines the url property to get and set the target URL and the headers property to add header strings to the request. If the request is going to be a POST, you set the body of the request through the body property. A request executes through the method invoke . The event completed informs you about the completion of the request.
Each Web request is executed through an internal class-the Web request manager-that employs an “executor” to open the socket and send the packet. The default executor class is
XMLHttpExecutor
. All
The Microsoft AJAX library defines just one HTTP executor-the
Sys.Net.XMLHttpExecutor
class. As the
|
Property |
Description |
|---|---|
|
responseAvailable |
Boolean property, indicates whether the response is available |
|
responseData |
Gets the response of the request as raw text |
|
started |
Boolean property, indicates whether the request has started |
|
statusCode |
Indicates the status code of the HTTP response |
|
statusText |
Indicates the status text of the HTTP response |
|
timedOut |
Boolean property, indicates whether the request has timed out |
|
xml |
Gets the response of the request as an XML document object |
In addition, the XML HTTP executor features methods to start and abort the request. Table 2-9 lists the methods of the class.
|
Property |
Description |
|---|---|
|
abort |
Aborts the ongoing request, if any |
|
executeRequest |
Sends the request to its target URL |
|
getAllResponseHeaders |
Gets all response headers in a single collection object |
|
getResponseHeader |
Gets the value of the specified header |
Note that the
abort
method aborts the current
XMLHttpRequest
call, which simply
| Note |
AJAX libraries are associated with the
XMLHttpRequest
browser object. So what else could an executor be other than an instance of the
XMLHttpRequest
class? In general, an HTTP executor is any means you can use to carry out a Web request. An alternative executor-which was removed from the Microsoft AJAX library in the Beta stage-is based on HTTP
|
The Sys.Net.WebRequest class and its derivatives serve the purpose of issuing client requests to a server resource. This is the engine behind client Web service calls. ASP.NET AJAX Extensions provides a large share of its functionalities through updatable panels. (See Chapter 4.) Updatable panels are portions of the page that can be refreshed independently of others and the same page as a whole. The PageRequestManager class is the Microsoft AJAX library class in charge of controlling the update of individual panels. Table 2-10 lists the members of the class.
|
Member |
Description |
|---|---|
|
isInAsyncPostback |
Boolean property, indicates whether the class is engaged in a panel refresh (also known as, asynchronous postback). |
|
abortPostback |
Method used to abort an ongoing panel refresh. The operation closes the underlying socket and
|
|
getInstance |
Static method used to return the singleton instance of this class available in the page space. |
For reasons that will become clear in Chapter 4, only one instance of this class is allowed per page. The class defines an event model that page authors can leverage to hook up the various stages in a panel refresh. We’ll return to this point in detail in Chapter 4.
The Microsoft AJAX library doesn’t define concrete user-interface components, such as classes that provide the client-side behavior of server controls. Instead, in the library you find only base classes to define three key categories of user interface components: behaviors, controls, and DOM elements. Web developers, as well as third-party
Client behaviors are components derived from the
Sys.UI.Behavior
class and are triggered by client events, such as mouse movements, keystrokes, timer
Multiple behaviors can be attached to the same HTML element; based on its functionality, the same behavior can be attached to distinct elements. The Microsoft AJAX library defines only the base class of client behaviors, but no built-in behaviors.
The constructor of the behavior class determines the binding between the behavior and a DOM element. The Sys.UI.Behavior class also features static methods to retrieve all behaviors attached to an element as well as look up behaviors by name and type.
The
Sys.UI.Control
class derives from
Sys.Component
and wraps a DOM element-
Sys.UI.Control = function Sys$UI$Control(element) { ... }
The class provides methods to add, remove, and toggle the cascading style sheet (CSS) style of the control and to initialize the underlying DOM subtree. The
raiseBubbleEvent
method
The Sys.UI.DomElement class represents a native DOM element. The class inherits from JavaScript’s Object and, as such, it’s not an Microsoft AJAX library component. The class has methods to add, remove, toggle, and check CSS styles and to locate child elements by ID. In addition, you can find methods to get and set the location of the element in the host page (x,y coordinates) and to get the bounding rectangle of the element.
DOM events are wrapped by instances of the Sys.UI.DomEvent class. The class lists methods to add a single handler, add multiple handlers, remove one handler, and clear all handlers. Table 2-11 details all methods.
|
Method |
Alias |
Description |
|---|---|---|
|
addHandler |
$addHandler |
Adds a handler for the event on the specified DOM element |
|
addHandlers |
$addHandlers |
Adds a collection of event handlers |
|
clearHandlers |
$clearHandlers |
Removes all handlers set on a given DOM element |
|
preventDefault |
Prevents the execution of the default task for the event |
|
|
removeHandler |
$removeHandler |
Removes a given handler set on the specified DOM element |
|
stopPropagation |
Stops the propagation of the event up the DOM subtree |
As you can see, the Microsoft AJAX library provides a shorthand notation to create DOM event hookups and removal. For example, you can use the $addHandler and $removeHandler aliases to add and remove a handler. Here’s the syntax:
$addHandler(element, "eventName", handler); $removeHandler(element, "eventName", handler);
Table 2-12 lists properties of the Sys.UI.DomEvent class.
|
Property |
Description |
|---|---|
|
altKey, ctrlKey, shiftKey |
Boolean properties denoting whether the Alt, Ctrl, and Shift keys were pressed when the event occurred. |
|
button |
Indicates the mouse button that was clicked, if any. Values are taken from the Sys.UI.MouseButton enumeration. |
|
charCode |
Gets the character code of the key that raised the associated event. |
|
clientX, clientY |
X, Y coordinates of the mouse event in the client area of the browser. |
|
keyCode |
Indicates the key that was hit, if any. Values are taken from the Sys.UI.Key enumeration. |
|
offsetX, offsetY |
X, Y offsets of the mouse position with respect to the clicked DOM element. |
|
rawEvent |
Gets the native event object as originated from the current browser. |
|
screenX, screenY |
X,Y coordinates of the mouse event in the screen. |
|
target |
Gets the DOM object that caused the event. |
|
type |
Indicates the type of event that occurred. |
In many cases, you’ll want to hook up several handlers to a DOM event for a component. Rather than manually creating all the required delegates and
initialize: function() { var elem = this.get_element(); $addHandlers( elem, {[ 'mouseover': this._mouseHoverHandler, '
mouseout
': this._mouseOutHandler, 'focus', this._focusHandler, 'blur', this_blurHandler ]}, this); }
The $clearHandlers alias, conversely, removes all handlers set for a particular DOM element in a single shot.
| Important |
If you write a component and wire up some events, it is essential that you clear all handlers when the component is unloaded, or even earlier, if you don’t need the handler any longer. For example, you should do that from the component’s dispose method to break circular references between your JavaScript objects and the DOM. Correctly applied, this trick easily prevents nasty memory leaks. |
Building cross-browser compatibility for events is not an easy task. Internet Explorer has its own
Another significant difference is in the way mouse and keyboard events are represented. The Microsoft AJAX library abstracts away any differences between browsers by providing ad hoc enumerated types, such as Sys.UI.Key and Sys.UI.MouseButton . Here’s some sample code:
function button1_Click(e) { if (e.button === Sys.UI.MouseButton.leftButton) { ... } } function keyboard_EnterPressed(e) { if (e.keyCode === Sys.UI.Key.enter) { ... } }
From within an event handler, the
this
pointer represents the DOM element the event was attached to. Note that the referenced DOM element isn’t
| Note |
You won’t receive any event data if you bind the handler via markup-for example, by setting the
onclick
attribute of an
<input>
tag. Everything said here applies only to event handlers added via methods (and aliases) of the
Sys.UI.DomEvent
class. Events bound through attributes are still
|
The Microsoft AJAX library contains a number of other miscellaneous components to provide additional facilities to ASP.NET AJAX developers. Let’s
The Sys.StringBuilder class adds advanced text manipulation capabilities to ASP.NET AJAX pages. As the name suggests, the class mimics the behavior of the managed StringBuilder class defined in the .NET Framework.
When you create an instance of the builder object, you specify initial text. The builder caches the text in an internal array by using an element for each added text or line. Table 2-13 details the members of the class.
|
Member |
Description |
|---|---|
|
append |
Adds the specified text to the internal array |
|
appendLine |
Calls append, and adds a new line character |
|
clear |
Clears the text stored in the builder |
|
isEmpty |
Checks whether the builder contains any text |
|
toString |
Returns the contents of the array as a plain string of text |
The StringBuilder object doesn't accept objects other than non-null strings. The toString method composes the text by using the join method of the JavaScript array class.
The Microsoft AJAX library String class is also enriched with a format method that mimics the behavior of the Format method on the .NET Framework String class:
alert(String.format("Today is: {0}", new Date()));
You define placeholders in the format string using {n} elements. The real value for placeholders is determined by looking at the n .th argument in the format method call.
Another class that is worth mentioning is the Sys._Debug class. An instance of this internal class is assigned to the Sys.Debug global object.:
Sys.Debug = new Sys._Debug();
In your pages, you use the Sys.Debug object to assert conditions, break into the debugger, or trace text. Table 2-14 details the methods available on the object.
|
Method |
Description |
|---|---|
|
assert |
Asserts that the specified condition parameter is true. |
|
clearTrace |
Erases the trace output. |
|
fail |
Breaks into the debugger. The method works only if the browser is Internet Explorer. |
|
trace |
|
|
traceDump |
Displays the specified object in a readable form. |
The assert method has the following prototype:
assert(condition, message, displayCaller);
If the condition is met, the method just exits and the execution continues with the
The clearTrace method takes no arguments and clears the portion of the page where ASP.NET AJAX-related trace messages are displayed. More precisely, the clearTrace method just hides the panel component that shows all trace messages.
The
traceDump
method writes the contents of the specified object in a
<textarea id="traceConsole" cols="40" rows="10" />
The traceDump method accepts two parameters, as shown here:
Sys.Debug.traceDump(object, name)
The name parameter indicates descriptive text to display as the heading of the object dump. The text can contain HTML markup. Figure 2-2 shows the results.
Figure 2-2:
The Microsoft AJAX library debugging tracer in action
Any text output through tracing is displayed in the Visual Studio 2005 Output window.
The trace method writes the text argument to the trace output. It takes only one parameter-the text to render.
The fail method breaks into the debugger, but only if the browser is Internet Explorer. What if you’re testing your ASP.NET AJAX application under another browser? You can’t use the Visual Studio debugger to step through client code running in Firefox or other Mozilla-based browsers. However, a Firefox debugger implemented as a Firefox extension can be downloaded from http://www.mozilla.org/projects/venkman .