In addition to delivering a considerable amount of Ajax functionality in an easy-to-use framework, ASP.NET AJAX provides a number of additions to JavaScript that can make client coding easier. Among these are OOP-style constructs, such as namespaces, inheritance, and interfaces, as well as client-side reimplementations that resemble .NET constructs such asStringBuilder. Also, selected JavaScript objects are enriched with new features.
ASP.NET AJAX Shortcuts and Helper Functions
By including the ASP.NET AJAXScriptManagercontrol into a web page, you automatically get a number of useful helper functions and shortcuts to important JavaScript features. Some of these new functions just save you some typing. Some of them, however, offer a much greater advantage: they are browser-agnostic. For instance, Internet Explorer on one side and all other modern browsers on the other side each provide their unique way to attach event listeners (see Chapter 2). The code in ASP.NET AJAX detects the browser type and automatically uses the appropriate function on every system.
Shortcuts
The method most often used by developers to create a modern JavaScript-powered web site is document.getElementById(). Several Ajax toolkits provide a shortcut for this rather lengthy method name called$(). ASP.NET AJAX tries to coexist with other frameworks and therefore is using a new name:$get().
Whereas this saves only a few characters, the new event handling helper functions are of greater value. When programmatically assigning a handler function to an event, you can use the$addHandler()function.
function $addHandler (element, eventName, handler) { }
You need to provide theelementattribute to attach the handler to theeventName(without the “on” prefix!), and the actualhandler(as a function reference or an anonymous function). Below is an example that pops up a warning window when a user clicks on a button:
When you want to assign handlers for several events for an element, you can either use several$addHandler()calls, or you use$addHandlers(), providing the element and an array of events and handler functions as arguments.
To remove a specific handler, use the$removeHandler()function demonstrated here:
function $removeHandler(element, eventName, handler) {}
Note that you have to pass the event-handler function again when removing the handler. Therefore, it is more convenient in most cases to call the$clearHandlers()function, which removes all handlers for a given element:
function $clearHandlers(element) {}
Adding Event Handlers, the Alternative Way
Apart from the $addHandler(),$removeHandler()and$clearHandlers()functions, ASP.NET AJAX also supports a special pattern for attaching handlers to element events: theadd_xxx()methods. For instance,Sys.Applicationis the ASP.NET AJAX JavaScript object that represents the current page. In order to execute code after the page has been fully loaded, you can code as shown here:
This is quite useful when using special client classes for DOM elements that are currently part of the ASP.NET AJAX Futures CTP. We will cover this in greater detail in Chapter 15.
The ASP.NET AJAX team tried very hard to recreate to a certain extent the ASP.NET page lifecycle in JavaScript. JavaScript itself only supports aloadevent, which is not enough for some applications. It also has a serious flaw: the event is fired when the HTML markup of the current page has been fully loaded. However, ASP.NET AJAX sites load several external JavaScript libraries. They are usually not available yet when the HTML has been fully rendered by the browser. Therefore, using the JavaScriptloadevent to start any ASP.NET AJAX coding is too early in the client page lifecycle.
Theloadevent defined by ASP.NET AJAX only runs when all external JavaScript files have been fully loaded. In order to execute code after the event has been fired, you have two options. You can either use theSys.Application.add_load()method (as described in the sidebar, “Adding Event Handlers, the Alternative Way”), or you can write a JavaScript function namedpageLoad(). When ASP.NET AJAX determines that all external files have been fully loaded, it executes thepageLoad()function, if it exists on the current page—quite similar to the way ASP.NET executes the server-sidePage_Load()method if it exists. This method provides a safe way to start using ASP.NET AJAX as early as possible.
function pageLoad(){ /* ...*/ }
At the end of a page, when the user closes the browser or navigates to another URL, theunloadevent occurs. You can execute code when this happens by writing a function calledpageUnload().
function pageUnload(){ /* ...*/ }
ASP.NET AJAX automatically executes such a function at the appropriate time, if it has been implemented.
For DOM elements, ASP.NET AJAX provides special methods for common scenarios like applying CSS classes. These methods are defined in theSys.UI.DomElementclass. For common features like setting CSS classes or removing them, CSS class methods take some keyboarding weight off developers’ shoulders.
Checks whether the CSS class definition of anelement contains a certain CSS class (className). If it does, it removes this CSS class, otherwise it appends the CSS class. Apart from CSS classes, ASP.NET AJAX provides helper methods for some of the most often accessed properties of general HTML elements: width, height, and position.
Sys.UI.DomElement.getBounds(element)
Returns an object with the propertiesx,y,height,width, containing the x coordinate, y coordinate, height, and width of the given element.
Sys.UI.DomElement.getLocation(element)
Returns an object with the propertiesxandy, containing the x and y coordinates of the given element.
Sys.UI.DomElement.setLocation(element, x, y)
Sets the x and y coordinates of the given element.
Another method defined withinSys.UI.DomElementisgetElementById()—but you already know the shortcut for that,$get().
None of these extensions alone is worth writing home about, but taken together, they can provide some real value if you write a lot of JavaScript code. Remember that a key idea of any Ajax framework is to dramatically reduce the amount of custom JavaScript code that needs to be written on top of the framework.
Instead of a complete list, we’ll present just one easily written example. The newArray.forEach()method applies a function to each element of a given array.
function Array$forEach(a, fnct){ for (var i = 0; i = a.length; i++) { if (typeof(a[i]) != "undefined") { fnct.call(null, a[i], i, a); } } }
However, the built-in ASP.NET AJAXforEach() method saves some typing, a bit of debugging, and a lot of extra maintenance work.
To facilitate OOP development, ASP.NET AJAX adds to JavaScript some OOP-type features, which are covered in this chapter. These include namespaces, abstract classes, and interfaces. The additional features are designed to help you design and write more structured client-side code. They can apply not only to Ajax applications, but also to any JavaScript code you write.
Namespaces
A key ASP.NET AJAX JavaScript OOP extension is the addition of namespace functionality. Namespaces enable you to encapsulate functionality into logical groups under a single name. They help avoid name collisions with functions that have the same name but fulfill different purposes. The JavaScript language specification does not specify namespaces, so the language itself cannot offer this functionality. However, ASP.NET AJAX uses a simple technique to emulate namespaces. You can create a new class (which serves as the “namespace”), then make another (new) class accessible as a property of the namespace class. This allows you to access your class using NamespaceClassName.YourClassName .
One of the base classes in ASP.NET AJAX runtime is theTypeclass. Two methods of this class come in handy when creating the ASP.NET AJAX namespaces:
Type.registerNamespace(name) Registers a namespace
Class.registerClass(name, base type, interface type) Registers a class as a member of the namespace
To demonstrate this technique, let’s create anOReilly namespace for a group of classes used in this book. Suppose that one of them is namedSoftwarewith two properties:nameandvendor. First, you must register theOReillynamespace:
Type.registerNamespace("OReilly");
Next, you create theSoftwareclass as a member ofOReillyusing the following code snippet:
OReilly.Software = function(name, vendor) { var _name = (name != null) ? name : "unknown"; var _vendor = (vendor != null) ? vendor : "unknown";
The class constructor expects values for the two properties. To perform data hiding, the class member values are saved as separate variables, and the class implements setter and getter methods for the properties. Note that JavaScript does not support private or protected properties. Therefore, all class members are public. The data hiding implemented here does not provide protection from unauthorized access; it is just a helper tool to structure code and make the data access coherent. Of course most technologies that do supportprivateorprotectedstill allow access to those properties using reflection.
Finally,OReilly.Softwaremust be registered as a class so that you can use it in your applications. You do this with theregisterClass()method. This method can take up to three parameters:
name The name of the class
base type The base type of the class, if any, as a reference to the type
interface type The interface type of the class, if any, as a reference to the type
TheOReilly.Softwareclass does not have a base type and does not implement an interface type. The call toregisterClass()registers the class, omitting the second and third parameters:
Type.registerClass("OReilly.Software");
ASP.NET AJAX implements several types, but the one you will use most often isSys.IDisposable(because you can write adispose()method that is called automatically when the script ends), even though JavaScript has only a simple garbage collector. However, you do not necessarily need to implement an interface. If you do not use an interface, the call toType.registerClass()is subsequently not necessary to access the new class. For more advanced features, this method call is mandatory (see the following sections).
Figure 4-1 shows the result displayed when the page is loaded.
Figure 4-1. Instantiating two objects within the same namespace
Although ASP.NET AJAX namespace classes are not real namespaces, they can make it easier for you to structure complex JavaScript code, with very little overhead.
Please check back next week for the conclusion to this article.