With the introduction of AJAX and mainly AJAX Client
Libraries, dealing with JavaScript for a non-professional JavaScript developer
is not a nightmare anymore! Now you can create your own client templates or
classes based on the prototype design pattern, add inheritance concepts, create
Interfaces, and Enums in an easy manner.
In this article, we will develop a client side class that
will encapsulate all of the functionalities needed by the application we are
developing. You could live without creating such a class, however, it is
recommended to go this way!
Let us first explain the concept of the class and why it is
needed. To be able to show a popup window on the page showing the information
coming from the server, we need a client side function that is capable of
accessing the AJAX Service and retrieve the required data, update and show the
popup window on the page, a function to hide the popup window, and a function
to run in case an error occurred during the processing of the AJAX Service
call. Therefore, the class we will be developing shall include all these
functions.
Again, in this article we are not going to cover all of the
details on the AJAX Client Side Libraries. We will only explain what is
required and needed by this article. However, if you are interested in covering
this topic in detail, we recommend you check the series of MSDN web casts on
AJAX Client Libraries presented by Rob Bagby (Microsoft Developer Evangelist).
You can have a look at this post
from Rob that lists all the web casts he has delivered and those coming soon!
The first thing to do is to add a new JavaScript file. We
will go step by step in explaining the code you would need to add:
Listing 6
Type.registerNamespace("MyServices");
We start by defining a new Namespace called MyServices. This
namespace will include the client side class we are developing. As you can see
the Namespace feature has been added to the JavaScript world!!
Then we need to define the constructor of the client side
class:
Listing 7
MyServices.Location = function (uiElement, uiBody) {
MyServices.Location.initializeBase(this);
this._uiElement = uiElement;
this._uiBody = uiBody;
this._xAxis = 0;
this._yAxis = 0;
}
The constructor of the template or class is nothing but a
normal JavaScript function as shown above. The constructor takes as input two
parameters:
uiElement
uiBody
Both parameters represent the popup window that will be
displayed on the page. In addition, two other private members are declared that
represent the position where the popup window shall be shown. Notice that it is
recommended to declare all your private members in the constructor of the
client side class.
Now that the constructor is defined, we will define the
functions and properties included in the class using the prototype design
pattern:
Listing 8
MyServices.Location.prototype =
{
get_uiElement: function()
{
return this._uiElement;
}
, set_uiElement: function(value)
{
this._uiElement = value;
}
,
get_uiBody: function()
{
return this._uiBody;
}
, set_uiBody: function(value)
{
this._uiBody = value;
}
,
The first things we define are public properties for the UI
elements in the class. The GET and SET properties are defined as two separate
functions in JavaScript.
Next, we will define the function that will do the service call
from inside the client-side:
Listing 9
ShowPopupinfo: function(event, areaName)
{
MyServices.LocationService.GetAreaInfo(areaName,
Function.createDelegate(this, this.OnCompleted),
this.OnError, // Failure Callback
this.OnTimeOut); // TimeOut Callback
this._xAxis = event.clientX;
this._yAxis = event.clientY;
}
The first line of the function above makes a call to the
GetAreaInfo function by utilizing a class named MyServices.LocationService and
accessing its method called GetAreaInfo. A very important note here to mention
is that, this method is not the one shown above in the ASMX Web service we
created above. This function call belongs to the Web Service Proxy class that
was created at run time as a client side proxy to access the ASMX Web service
on the server. Don’t mix both! To understand what we are talking above, please
follow the instructions mentioned above on how to get more information on the
Web Service Proxy class.
The MyServices.LocationService.GetAreaInfo function takes as
input the parameter required by the server side GetAreaInfo method, a reference
to a callback function that will be fired when the response is received from
the server, a reference to a callback function that will be fired when an error
occurs during the processing of the service asynchronous request, a reference
to a callback function that will be fired when a time-out happens.
Notice that the success callback function is covered by
Function.createDelegate(). The reason we have added this statement is to make
the AJAX environment call the success callback function on the same instance of
the class that fired the call to the Web service. This is mainly helpful, when
you need to reference properties and functions of the client side class, which
did the asynchronous service call to the server, inside the callback functions.
So to sum it up, adding the above statement would make accessing properties and
functions from the instance of the client side class that did the call to the
Web service safe and accurate. Without this, the instance of the client side
class that did the asynchronous call would be null, since the response of the
Web service will be executing in a different context than the one used to send
the request asynchronously to the Web service. This is a very important hint I
owe it to Rob Bagby who explained it to me in details. Thank you Rob!!
Going back to the ShowPopupInfo function, the last two lines
are simply setting the value of the two private members, xAxis and yAxis, using
the event input parameter that contains among other useful information the
position of the mouse where it was clicked on the page. The goal here is to
show the popup window as close as possible to the location where the user has
clicked his/her mouse.
The next function to discuss is the callback function that
will be called when the response is received successfully from the server:
Listing 10
OnCompleted: function(result, userContext, methodName)
{
var uiElement = $get(this.get_uiElement());
var uiBody = $get(this.get_uiBody());
if (uiBody != null)
{
var textNode = uiBody.firstChild;
if (!textNode)
{
textNode = document.createTextNode(result);
uiBody.appendChild(textNode);
}
else
{
textNode.nodeValue = result;
}
if (uiElement != null)
{
uiElement.style.visibility = "visible";
uiElement.style.display = "inline";
uiElement.style.left = this._xAxis + "px";
uiElement.style.top = this._yAxis + "px";
}
}
}
,
The sole idea behind the above function is simply, set the
data returned from the server into the popup window area and then make sure the
popup window is now shown on the page.
The other functions in the client side class will not be
discussed here due to the fact that they are too simple to discuss.
Once you have written the above client side class, you need
to tell the AJAX environment to register the class on the client side to be
accessible by client-side functions and the way to do so is simply adding this
line of JavaScript code:
Listing 11
MyServices.Location.registerClass("MyServices.Location");
Up to this point, the client side class MyServices.Location
is successfully defined. We will add few utility methods that will be called by
controls on the ASPX page. These methods can be easily placed on the page
itself inside a Script block, however, it is recommended to place all your
JavaScript code in one place and then configure the ScriptManager on the ASPX
page with a Script Reference so that when the page is rendered it will include
a script tag referencing the JavaScript file including all user-defined
functionalities.
First of all, we need to define a new instance of the client
side class whenever the page loads. To do so, we will use the pageLoad function
that is part of the Application class added newly to the AJAX environment.
Listing 12
var location = null;
function pageLoad(sender, args) {
location = new MyServices.Location("modal", "modalBody");
location.HidePopupInfo();
}
The code above, simply creates a new instance of the MyServices.Location
class and calls a function that is part of the client side class to hide the
popup window on the page. The reason why we created the instance of the client
side class in the pageLoad function is that, when the AJAX environment reaches
the pageLoad function, all the AJAX client side and user defined JavaScript
code has been successfully loaded, so at this stage it is safe to access any
user or system defined JavaScript code.
Another function will be created is the GetAreaInfo
function. We could have made the clickable hot spots directly call the
ShowPopupInfo function defined on the MyServices.Location class, but to make
the HTML part of the page independent of the class instance name, we have added
this function that will be called by the hot spots on the page, passing the
event argument and the text representing the area hovered over! The function
simply makes a call to the ShowPopupInfo function on the defined instance of
the MyServices.Location class.
If you have reached this stage, this means that you have
finished developing your AJAX-enabled HTML ImageMap control and ready to browse
the ASPX page and hover over the image displayed.