Launch Visual Studio 2005 and select template "ASP.NET
AJAX-enabled Web Site" to create a web site named AjaxCustCom,
as well as select Visual C# as the built-in language. Next, right click the
project and select "Add new Item…" to create a Jscript file named
AjaxCustCom.js.
For clarity, let us depict a sketch to illustrate the
relationship between the two components we are to create in JavaScript.
Figure 2: Relationship between the two components: Class
and Student

Programming the Two Components in JavaScript
Open file AjaxCustCom.js and input the following code.
Listing 2: Define the two components in JavaScript
Type.registerNamespace("Samples");
Samples.Student = function(number,gender,name){
Samples.Student.initializeBase(this);
this.Number = number;
this.Gender = gender;
this.Name = name;
}
Samples.Student.prototype = {
initialize: function() {
Samples.Student.callBaseMethod(this,"initialize");
},
get_Number: function() {
/// <value type="Number"></value>
if (arguments.length !== 0) throw Error.parameterCount();
return this.Number;
},
set_Number: function(value) {
var e = Function._validateParams(arguments,
[{name: "value", type: Number}]);
if (e) throw e;
this.Number = value;
},
get_Gender: function() {
/// <value type="String"></value>
if (arguments.length !== 0) throw Error.parameterCount();
return this.Gender;
},
set_Gender: function(value) {
var e = Function._validateParams(arguments,
[{name: "value", type: String}]);
if (e) throw e;
this.Gender = value;
},
get_Name: function() {
/// <value type="String"></value>
if (arguments.length !== 0) throw Error.parameterCount();
return this.Name;
},
set_Name: function(value) {
var e = Function._validateParams(arguments,
[{name: "value", type: String}]);
if (e) throw e;
this.Name = value;
},
dispose: function() {
this.Number = null;
this.Gender = null;
this.Name = null;
Samples.Student.callBaseMethod(this, "dispose");
}
}
Samples.Student.registerClass("Samples.Student", Sys.Component, Sys.IDisposable);
Samples.Class = function()
{
Samples.Class.initializeBase(this);
this.Number;
this.Address;
this.Students = [];
}
Samples.Class.prototype = {
initialize: function() {
Samples.Class.callBaseMethod(this,"initialize");
},
get_Number: function() {
return this.Number;
},
set_Number: function(value) {
this.Number = value;
},
get_Address: function() {
return this.Address;
},
set_Address: function(value) {
this.Address = value;
},
addStudent: function(student){
/// <value type="Samples.Student"></value>
if (Object.getTypeName(student) != "Samples.Student")
{
var e = Error.argumentType("student", Object.getType(student),
Samples.Student,"Samples.Student required!");
e.popStackFrame();
throw e;
}
Array.add(this.Students,student);
},
removeStudent: function(student)
{
Array.remove(this.Students,student);
},
get_Students: function()
{
return this.Students;
},
dispose: function() {
this.Number = -1;
this.Students = null;
this.Address = null;
Samples.Class.callBaseMethod(this, "dispose");
}
}
Samples.Class.registerClass("Samples.Class", Sys.Component, Sys.IDisposable);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Here, we first declared a namespace Samples,
and then we started to define two components, Student
and Class, in the namespace. Typically, you should
define properties within the constructor, and define the get and set accessors
of the properties, methods, and event handlers inside the prototype block. Note,
inside all of these you are suggested to validate the necessary parameters
first with effective means, such as arguments, Function._validateParams, etc., before putting them into use.
Here we have followed the general routines. Since the later two samples will further
discuss them, we are not to detail them any more.
On the whole we have defined two simple components, with the
second component Class as the container of the first
component Student.
Create the Components on the Client Side
Now, let us see the client-side code.
Listing 3: Client-side JavaScript code to create
the two components
…………………………
<script type="text/javascript">
var class01,class02,classes=[];
function pageLoad(sender, args){
class01 = new Samples.Class();
class01.set_Num(1);
class01.set_Address("Address for Class 01");
class01.addStudent(new Samples.Student("1001","male","Mike"));
class01.addStudent(new Samples.Student("1002","male","John"));
class02 = new Samples.Class();
class02.set_Num(2);
class02.set_Address("Address for Class 02");
class02.addStudent(new Samples.Student("2001","male","Jack"));
class02.addStudent(new Samples.Student("2002","male","Sam"));
class02.addStudent(new Samples.Student("2003","female","Jenny"));
Array.add(classes,class01);
Array.add(classes,class02);
}
function btnTest_onclick() {
Sys.Debug.trace('Start the test!');
Sys.Debug.traceDump(class01,'Details about class01:');
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="AjaxCustCom.js" />
</Scripts>
</asp:ScriptManager>
<div style="width: 549px; height: 1px">
<h1 style="color:Coral">
<span style="color: navy">Client Side Custom Component Test</span></h1>
</div>
<hr style="width: 507px" align="left" />
<input id="btnTest" type="button" value="Start to Test" language="javascript"
onclick="return btnTest_onclick()" />
<br />
<textarea id='TraceConsole' cols="60" style="height: 277px"></textarea>
Seen above, the three global variables that were first declared
used to hold related class instances later. Then inside MS AJAX typical startup
function—pageLoad
we created two instances for class Class. We then called
their property-related set accessors to set the property values. Next, we
called method addStudent to add new sub object—instances of class Student
to the parent variables. Last, we added the two Class
instances to an MS AJAX special Array object. That is
it!
In the last part of the above code, we defined a special
HTML <textarea> element named "TraceConsole"
which was a good means to debug MS AJAX based applications. Here, when we click
"Start to Test," the related click handler btnTest_onclick will be
invoked, and the <textarea> "TraceConsole" will
be stuffed with the interesting debugging information, as shown in Figure 3.
Figure 3: Run-time snapshot for Sample 1
