Abstract
Part 1 of this series described the object-oriented
features of JavaScript. Part 2 built upon that
knowledge and introduced a framework supporting class inheritance. In this final
installment, we'll use Cfx
to construct a JavaScript control class
hierarchy that offers rich client-side behaviors to ASP.NET user controls.
Introduction
A web control represents a portion of the web page that typically provides
user interaction such as text boxes, radio buttons, check boxes, etc. Web
control can be static as well. Subdividing pages into controls improves
abstraction by making pages containers of web controls and enhances reuse and
extensibility.
With ASP.NET, you can use conventional HTML elements or ASP.NET controls. You
can augment them with defining your own user controls. Eventually ASP.NET
renders all controls into HTML and JavaScript interpreted by the client browser.
Naturally, you can write your website and use the default ASP.NET behaviors.
However this is not feasible in all situations and limits the user experience.
Using Cfx
you can now achieve greater control and richness to your
client-side scripts writing object-oriented JavaScript.
Note - A detail explanation of ASP.NET and web controls is beyond the
scope of this article as there are many great books and essays on ASP.NET. The
aim of this article is to show how Cfx
is used to build classes
that take advantage of ASP.NET to build rich clients.
The Strategy
Leveraging ASP.NET Control Names
ASP.NET applies a consistent naming scheme to its controls using the
id
and name
attributes when it renders them as HTML
elements. ASP.NET names HTML elements using the element name proceeded by the
names of its containers separated by an underscore. For example, in accompanying
demo, the ASP.NET CfxText
user control encapsulate the ASP.NET
textbox control giving it the identifier txtField
.
<asp:TextBox id="txtField" runat="server" maxlength="255"></asp:TextBox>
The ASP.NET CfxText
user control has the id txtName
and is subsequently encapsulated by a CfxWebFormOptions
control
with the id CfxWebFormOption1
. The id generated by ASP.NET for the
HTML text element uses the outermost container identifier followed by the
separator character continuing with the name of the next container and then
finally followed with the control identifier.
<input id="CfxWebFormOptions1_txtName_element" type="text"
maxlength="255" class="LgNorm" style="width:224px;" />
By leveraging this naming convention, we can logically group control elements
and develop a class hierarchy of ASP.NET control wrappers in JavaScript
providing client side behavioral support to the ASP.NET user controls.
Note - ASP.NET 2.0 uses a dollar sign ($) character as the separator
character. The dollar sign eliminates ambiguities caused by the underscore
separator where it can be used in identifiers.
Cfx.Dom.GetElementTerms
uses a regular expression that accounts for
underscore ambiguities when splitting ASP.NET identifiers into element terms.
The JavaScript Control Class Hierarchy
CfxControl
conceptually represents the set of user control
classes used on the page. These classes represent a layout description along
with its client side behavioral definition. The layout description is defined
using ASP.NET and maintained in the accompanying .aspx
and
.cs
files. The client side behaviors are written in JavaScript in
corresponding .js
files. Thus client behavior is separated from its
layout. Notice that we have nearly a one-to-one correspondence between the
rendering files and the JavaScript files. The additional JavaScript files
contain common base class definition and implementation defined in the
CfxControl
and CfxInput
classes.
At the top level of the JavaScript control class hierarchy is the
Object
class followed by the CfxControl
class and is
the root of all JavaScript controls. The CfxWebFormOptions
control
is the container class for the input controls on the WebForm1
page.
There are three input controls deriving specific functionality from the
CfxInput class. The CfxText
class represents a
control for text input. The CfxSelect
class represents a single
selection dropdown and CfxLabel
wraps the ASP.NET
Label
control. CfxRadioSet
represents a group of radio
elements. The CfxHistoryOptions
class contains the
CfxRadioSet
and the CfxSelect
classes providing a
single control for making "historical" selections.
A couple of helper classes that are not part of the CfxControl
heirarchy are provided. The CfxError
class extends the
Error
class adding the framework object throwing the exception and
the CfxEvent
wrapper for JavaScript event
objects.
Figure 1. CfxControl class hierarchy.
JavaScript Client-side Controls
CfxControl
The CfxControl
class is the base class for all derived controls
and encapsulates properties inherited by all controls. The name property is the
name of control. Think of controls as document element containers and it is the
name of the container the name
property represents. The
parent
property is the parent CfxControl
. The items
property is an array of document elements that has the control name as part of
its id
attribute.
Figure 2. ASP.NET control identifier and terms.
For example when the
CfxWebFormOptions
control named
CfxWebFormOptions1
is
created, all the elements and images in the document that contains the string
CfxWebFormOptions1
in the
id
attribute are added to
the items array of the
CfxControl
.
CfxInput
The CfxInput
class is the base class for input controls. This
class defines input controls as having an input element property
element
and an image property image
indicating the
error state of the input control. It defines several base methods to manipulate
the image property and an Initialize
and Validate
method. CfxInput
is not defined as an abstract class and can be
instantiate. This is useful for situations needing a generic input control
object.
CfxText
The CfxText
control wraps the text input element and validates
its input against the regExp regular expression property. The control also
provides the ability to sink the onkeypress
event inspecting for an
the enter key to start validation. Users provide a handler in the event the
enter key is pressed via the CfxText
control
SubmitHandler
method.
this.txtName.SubmitHandler( OnEnterKey );
Figure 3. Setting SubmitHandler of txtName control to OnEnterKey handler.
If the submit handler is supplied, during the text input element
onkeypress
event, execution is transferred to the
CfxText
control OnEnterKey
method. The
CfxEvent
class wraps the JavaScript event object and inspects for
the enter key event. If the enter key event was pressed, the
OnEnterKey
method calls CfxText
submit handler.
function OnEnterKey( evnt )
{
var cfxEvent = new CfxEvent( evnt );
if ( cfxEvent.IsEnterKey() )
{
var thisObj = cfxEvent.FindInstance( CfxText );
return thisObj.submit;
}
else
return true;
}
Figure 4. CfxText OnEnterKey event handler.
Fired by the onkeypress
event, OnEnterKey
method
this
reference does not refer to a CfxText
instance
but to the event source element. FindInstance
is used to obtain the
instance of CfxText
associated with the source element. In order
for FindInstance
to determine the instance, the
CfxText.instance
flag is set to true
in its class
definition.
CfxSelect
The CfxSelect
control wraps a single selection dropdown input
element providing method to add and delete elements to and from the dropdown.
CfxSelect
also provide accessors methods to obtain the selected
text and value as well as the index of the selected element.
CfxLabel
The CfxLabel
wraps the ASP.NET Label
control
providing an interactive way of alterting page text. ASP.NET renders its labels
as span
elements and CfxLabel
locates it through its
id
attribute constructed by appending together the names of its
ancestor controls. The Value
accessor updates the inner text of
the span element. Rather than using alerts, CfxLabel
can be used
to enhance the display of error notifications.
CfxRadioSet
The CfxRadioSet
control wraps a group of radio input elements.
ClickHandler
method sets the onclick
event handler of
the radio button elements. GetElement
returns the
CfxRadioSet
radio button element from the radio button index.
GetIndex
returns the index of the CfxRadioSet
radio
button element. The GetItems
method inherited from
CfxControl
is overridden by CfxRadioSet
, because radio
elements are grouped by the name
attribute while the base method
uses the id
attribute to find elements. The
GetSelected
method returns the checked radio element, and
Length
returns the number of radio elements in
CfxRadioSet
.
CfxHistoryOptions
This control provides the client-side functionality of the set of elements
that simulate selecting history criteria. This control provides the
functionality for the CfxRadioSet
control and the controls
associated with the radio buttons.
Figure 5. CfxHistoryOptions user interface.
CfxHistoryOptions
groups the control into a
CfxRadioSet
control containing of a list of the radio elements as
well as the radio element affiliations. For example the radioSet
property contains the radio elements: radDefault
,
radByMonth
, and radByYear
. The radByMonth
radio input element affiliate is the CfxSelect
control named
radByMonth_selByMonth
control and radByYear
radio
input element affiliate is the radByYear_selByYear
control. The
radDefault
radio element has no affiliates. The value
attribute of the radio element identifies affiliates thus
CfxHistoryOptions
class can group elements containing that value.
In this case radByMonth
radio input affiliation consists of the
elements radByMonth
radio and radByMonth_selByMonth
dropdown.
Figure 6. Grouping radio element affiliate controls.
During initialization, CfxHistoryOptions
establishes on an
onclick
event handler for the radio set. When a radio element is
clicked the OnRadioClick
handler is called altering the disable
state of the radio affiliates. Notice that the handler uses the
CfxEvent
class FindInstance
method to
obtain the instance of the CfxHistoryOptions
class from the event
source element. Finally, the Validate
method verifies selections.
Cfx Wrapper Classes
CfxError
This wrapper class augments the JavaScript Error
object adding a
property that references the instance of the Cfx
class throwing the
exception. As you will see in the demo, the thrown CfxError
object
is used identify and change the state of the throwing CfxText object.
CfxEvent
The CfxEvent
class is a wrapper for JavaScript
event
objects. The event
object contains the
information about JavaScript events and passed along to CfxControl
event handlers. CfxEvent
hides browser variations of the
event
object providing a consistent interface. In the demo,
CfxControl
event handlers are responsible for detecting the enter
key event, the radio button check event, and the submit button click event. The
handlers create a CfxEvent
object to wrap the event
object and calls FindInstance
to translate the element firing the
event into its corresponding CfxControl
instance.
Code In Front
The final implementation of the controls occurs in the JavaScript of the
WebForm1
page. When WebForm1
loads, the
onload
event calls the page�s OnLoad
function
instantiating a new CfxWebFormOptions
control and assigns it to
formOptions
. The SubmitHandler
method assigns the
OnSubmit
event handler that gets called when the control submit
button click event occurs or the enter key is pressed from a text control.
OnSubmit
then calls the Validate
method and performs a
postback if the validation succeeds.
<script type="text/javascript">
function OnLoad()
{
formOptions = new CfxWebFormOptions( "CfxWebFormOptions1" );
formOptions.SubmitHandler( OnSubmit );
}
function OnSubmit()
{
if ( formOptions.Validate() == true )
Cfx.Dom.PostBack();
else
return false;
}
<script>
<body topmargin="0" leftmargin="0" marginheight="0" marginwidth="0"
onload="OnLoad();">
Figure 7. WebForm1 page code in front are now trivial routines.
Benchmarks
Cfx
performs surprisingly well. The demo program includes alerts
displaying page load and submission performance. For a 2GHz system, the time for
each task was under 35 milliseconds for IE 6.0 and under 50 milliseconds for
Mozilla 1.4.
Demo
The ControlDemo
demo program, shows how to design and implement
a control class heirarchy using Cfx
. The approach to this
application is to have ASP.NET responsible for the page layout and JavaScript
responsible for client-side user interactions.
The URL for this application is
http://localhost/JsOOP/ControlDemo/WebForm1.aspx. Copy the source code
into the JsOOP/ControlDemo subdirectory of your
http://localhost home directory. You can use Visual Studio to create
the ASP.NET project or use the IIS management tool found in Administrative Tools
of the Control Panel. This demo has been tested on both version 1.0 and 1.1 of
the runtime.
Conclusion
This series on object-oriented programming in JavaScript is an attempt to
fill in an astonishing gap in the development of client-side scripts. Too often
scripts are written as procedural adjuncts rather than as reusable objects. Much
of the reason for this, has to do with JavaScript books simply failing to fully
explain the language's object-oriented capabilities and no intrinsic support of
class inheritance. Another contributing factor is ASP.NET itself where the
programming model suggests writing JavaScript as procedural adjuncts for ASP.NET
controls.
Cfx
, provides an easy to use coding pattern for writing class
hierarchies in JavaScript. The result of writing object-oriented scripts is
richer client-side functionality by having JavaScript take on greater
responsibility of UI management. While ASP.NET defines page layout, the code
behind becomes trivial enabling the server-side code to be better focused on the
business logic.
On the other hand it may be useful to have the ASP.NET controls emit
JavaScript. Using Cfx
you can still structure your scripts in an
object-oriented fashion. Cfx
is quite versitile letting you choose
the deployment that works best for you.
Another advantage of Cfx
is that it enables you as a web
developer to retain greater control of your code. ASP.NET is powerful but too
much reliance on any tool from a single vendor can spell trouble when targeting
multiple platforms and browsers. Cfx
, because it is
object-oriented, makes it easy to isolate idiosyncrasies in fa�ades and
wrappers. While the demos are written for ASP.NET, Cfx
is a
JavaScript framework that is not specific to ASP.NET.
I hope that the JavaScript Class Framework elevates the quality of
client-side scripts promoting rich web-based interfaces, reduce vendor
dependencies, and promote the building of a collection of reusable JavaScript
classes.
Revision History
- Version 1.0 -- Initial Version
- Version 1.1 -- Fixed content errors.