Flylib.com

Books Software

 
 
 

Core Components


Core Components

The AJAX client library is made up of three main logical layers : JavaScript extensions, core framework classes, and user -interface (UI) framework classes. (See Figure 2-1.)

image from book
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 methods to simulate object-oriented constructs such as classes, namespaces, inheritance, and interfaces. The UI framework includes base components to define client behaviors, controls, DOM elements, and input devices such as keyboard and mouse buttons . The UI framework also incorporates as private elements classes that provide the client object model for a couple of ASP.NET AJAX server controls, namely Timer and UpdateProgress . We’ll cover these controls in Chapter 4, “Partial Page Rendering.”

The core framework classes form a sort of base library that incorporates a set of commonly used classes for event handling, string manipulation, Web services, debugging, and network operations. As you saw earlier, the Microsoft AJAX library supports namespaces, so classes in the client library belong to a particular namespace. Most classes in the base framework layer of the library belong to the Sys namespace.

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 Sys.Application Object

The execution of each ASP.NET AJAX page is controlled by an application object that is instantiated in the body of the library. The application object is an instance of a private class-the Sys._Application class. As mentioned, JavaScript has no notion of private members; therefore, private members are conventionally indicated by the underscore symbol (_) in their names .

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 nerve center of the ASP.NET AJAX page.

Generalities of the Sys._Application Class

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.

Table 2-3: Members on the Sys._Application Class
Open table as spreadsheet

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

Removes the specified component from the page hierarchy

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.

Looking Up Components

The findComponent method scrolls the runtime hierarchy of components for the current page until it finds a component with a matching ID. The method has two possible prototypes :

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 subtree rooted in the context object. The id parameter must be a string; the context parameter must be an Microsoft Client library object. The method returns the object that matches the ID, or it returns null if no such a object is found.

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.

Events in the Page Lifetime

Table 2-4 lists the events fired by the Sys._Application class. Listeners for these events can be added via script code.

Table 2-4: Client Events on the Sys._Application Class
Open table as spreadsheet

Event

Description

Init

Occurs when the page is first initialized

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 tasks .

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:ScriptManager

runat

="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.

The Sys.Component Object

Generally, the term component denotes an object that is reusable and can interact with other objects in the context of a framework. The term control , on the other hand, denotes an object that is sort of a specialized component. The main trait that differentiates components and controls is the user interface. Components are non-UI objects; controls are primarily UI-based objects.

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.

The Sys.Component Class

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.

Table 2-5: Properties of the Sys.Component Class
Open table as spreadsheet

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.

Table 2-6: Methods of the Sys.Component Class
Open table as spreadsheet

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 terminated

initialize

Performs any task required to initialize the component

raisePropertyChanged

Raises the propertyChanged event.

In addition to the members considered so far, the class fires a couple of events: disposing and propertyChanged . The former event occurs when the component is being disposed of; the latter event occurs when the state of the component is updated. The propertyChanged event is part of the INotifyPropertyChange interface.

Detecting Property Changes

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 callers that the value of a given property has been updated. Here’s a sample implementation of a component property:

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.

Batched Updates

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 group updates in calls to the beginUpdate and endUpdate methods. When a batch update operation is in progress, the value of the isUpdating property is automatically set to true .

Depending on the specific component, batch updates can improve performance and minimize screen updates.

The $create Alias

The $create alias provides a concise syntax for creating an Microsoft AJAX library component. It is mapped to the static method create on the Sys.Component class with the following prototype:

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 assigns it a click event handler, button1_Click , and ties it to the DOM element control sendDataButton :

$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 .

Component Disposing

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 destroyed .

The Network Stack

AJAX libraries in general, and ASP.NET AJAX Extensions in particular, owe their growing popularity to their ability to execute out-of- band Web requests from the client. In particular, ASP.NET AJAX Extensions allows you to invoke Web service methods as well as static methods defined on the server ASP.NET page class. This ability leverages the networking support built into the Microsoft AJAX library.

The Sys.Net.WebRequest Class

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.

Table 2-7: Properties of the Sys.Net.WebRequest Class
Open table as spreadsheet

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 executors derive from a common base class-the Sys.Net. WebRequestExecutor class.

The XML HTTP Executor

The Microsoft AJAX library defines just one HTTP executor-the Sys.Net.XMLHttpExecutor class. As the name suggests, this executor uses the popular XMLHttpRequest object to execute the HTTP request. Table 2-8 lists the properties of the class.

Table 2-8: Properties of the Sys.Net.XMLHttpExecutor Class
Open table as spreadsheet

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.

Table 2-9: Methods of the Sys.Net.XMLHttpExecutor Class
Open table as spreadsheet

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

{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}

Note that the abort method aborts the current XMLHttpRequest call, which simply closes the socket through which the client is expecting to receive response data, sets the aborted flag to true, and then fires the completed event. None of this affects any operation that might be executing on the server.

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 frames . The idea is to use a dynamically created inline frame to download the response of a given request and then parse that result into usable objects.

The Sys.WebForms.PageRequestManager Class

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.

Table 2-10: Members of the Sys.WebForms.PageRequestManager Class
Open table as spreadsheet

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 prevents any further page updates.

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.

User-Interface Components

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 vendors , can use these base classes to provide additional behaviors and client-side controls.

The Sys.UI.Behavior Class

Client behaviors are components derived from the Sys.UI.Behavior class and are triggered by client events, such as mouse movements, keystrokes, timer ticks , and DOM-based events. When triggered, behaviors can do virtually everything: update properties, run animations, implement drag-and-drop, and more. The goal of client behaviors is to enrich the behavior of an HTML element.

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

The Sys.UI.Control class derives from Sys.Component and wraps a DOM element- ideally , the DOM subtree of the matching server control. The binding between a Sys.UI.Control object and a DOM element is set in the class constructor.

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 bubbles up any DOM event detected in the control’s subtree. When this happens, the onBubbleEvent event is fired.

The Sys.UI.DomElement Class

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.

Handling DOM Events

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.

Table 2-11: Methods of the Sys.UI.DomEvent Class
Open table as spreadsheet

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.

Table 2-12: Properties of the Sys.UI.DomEvent Class
Open table as spreadsheet

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 related handlers, you can use a condensed syntax to add and remove multiple handlers:

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.

A Cross-Browser Model for Events

Building cross-browser compatibility for events is not an easy task. Internet Explorer has its own eventing model and so do Firefox and Safari. For this reason, the event model of the Microsoft AJAX library is a new abstract application programming interface (API) that joins together the standard W3C API and the Internet Explorer nonextensible model. The new API is closely modeled after the standard W3C API. In addition to using different method names ( add/removeEventListener is for Firefox, and attach/detachEvent is for Internet Explorer), browsers differ in the way they pass event data to event handlers. In Internet Explorer, an event handler receives its data through the global window.event object; in Firefox, the event data is passed as an argument to the handler. In the Microsoft AJAX library, event handlers receive a parameter with proper event data. You use the members on the Sys.UI.DomEvent class to execute common event-related operations regardless of the host browser.

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 necessarily the element that triggered the event. For example, if the event is bubbled up you might catch an event from, say, a <div> that was fired by a child button. In this case, you reach the trigger element using the target property listed in Table 2-12. Finally, if you’re registering handlers from a component and use delegates to reference event handlers, the this keyword refers to your component, not DOM elements.

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 processed , but you have to resort to your knowledge of the browser’s event model to correctly grab associated information.

Other Components and Functionalities

The Microsoft AJAX library contains a number of other miscellaneous components to provide additional facilities to ASP.NET AJAX developers. Let’s briefly focus on a few of them, starting with the script version of a popular .NET Framework managed class-the StringBuilder class.

String Manipulation

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.

Table 2-13: Members of the Sys.StringBuilder Class
Open table as spreadsheet

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.

Debugging Facilities

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.

Table 2-14: Methods of the debug Object
Open table as spreadsheet

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

Writes the text argument to the trace output.

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 next instruction. If the condition is false , the method displays a message box with the specified message. If the displayCaller parameter is true , the method also displays information about the caller.

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 human-readable format in the Microsoft Client library trace area. The trace area is expected to be a <textarea> element with an ID of traceConsole . You can place this element anywhere in the page:

<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.

image from book
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 .