Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

From Simple JavaScript Classes to ASP.NET AJAX Controls

0.00/5 (No votes)
29 Jan 2010 1  
Understanding OOP in ASP.NET AJAX extensions.

Table of Contents

Introduction

In this article, I'll cover the OOP principles in the MS AJAX JavaScript library. It is quite a big topic, but I decided to highlight only the essential things that should be known by developers for creating server side controls extended by client capabilities.

This article could also be useful as a quick help if you don't remember how exactly to work with some OOP extensions in the MS AJAX JS Library.

What knowledge will you get by reading this article?

You will understand how the ASP.NET AJAX controls work. You will understand their client side code, and thus able to debug and discover problems faster.

Prerequisite knowledge

I assume the reader knows the basics of ASP.NET development, and also the basic terms related with Object Orientated Programming (OOP). It is good to know what the terms class, object, interface, enumerator, and inheritance mean.

Download

Each code listed in this article has a description below itself. The description contains the path to the file in the download package. Each code is included in the example page, so you can simply run it from Visual Studio and see how it works.

How to include the MS AJAX JavaScript Library to your web page

The MS AJAX JavaScript Library is only a bunch of files with a js extension. These files are precompiled as embedded resources in the system.web.extensions.dll assembly. By putting the ScriptManager control into your page, you ensure that the library will be loaded.

Note: The ScriptManager control takes care of loading JavaScript resources into your web page. It is available from ASP.NET 3.5. If you decide to use the ScriptManager, you should register all the JavaScript resources via this control. By using this, you can avoid many problems caused by wrong loading of JavaScript. There is much to tell you about the ScriptManger but it's not the topic of this article, therefore if you are interested in it, take a look at reference [2].

OOP extensions

Let's start with OOP extensions. Basically, the big advantage (from my point of view) is that MS AJAX JavaScript Library allows you to think JavaScript as an OOP language. In the sections marked with "OOP extensions ...", I'll introduce some of the techniques to work with classes, inheritance, and enumerators.

OOP extensions - Creating a class

In this example, I will show you how to create a class, how to make an instance of it, and how to call a method on that instance.

//
// Define namespace. Namespace is DotNetSources and class name will be Customer.
//
Type.registerNamespace("DotNetSources.Customer");

//
// This is a constructor. Could be parametrized or parameterless.
//
DotNetSources.Customer = function() {
    
    // define class valiables
    this._name = null;
    this._dateOfBirth = null;
}

//
// Define a prototype. Imagine it's the set of methods on the class.
// Prototype for class Customer in namespace DotNetSources.
//
DotNetSources.Customer.prototype = {

    //
    // Methods
    //
    toString: function() {
        return "Name: " + this.get_name() + 
               ", Date of birth: " + this.get_dateOfBirth();
    },
    
    displayInfo: function() {
        alert(this.toString());
    },

    //
    // Properties
    //
    get_name: function() {
        return this._name;
    },

    set_name: function(value) {
        this._name = value;
    },

    get_dateOfBirth: function() {
        return this._dateOfBirth;
    },

    set_dateOfBirth: function(value) {
        this._dateOfBirth = value;
    }

}

DotNetSources.Customer.registerClass('DotNetSources.Customer');
Listing 1 - The class definition (01_creating_class/Customer.js)

As you can see, it's a simple class named Customer in the namespace DotNetSources. The class contains two variables (two properties): name and dateOfBirth. Let's look at the code to call it:

<div>
    Name: <input type="text" id="txtName" /><br />
    Date of Birth: <input type="text" id="txtDateOfBirth" /&gt<br />
    <input type="button" 
      value="Create class and call DisplayInfo method." 
      onclick="btnClick()" />
</div>

<script language="javascript">
    function btnClick() {
        // create instance
        var myCustomer = new DotNetSources.Customer();
        // set properties
        myCustomer.set_name($get('txtName').value);
        myCustomer.set_dateOfBirth($get('txtDateOfBirth').value);
        // call method on the instance of of Customer class
        myCustomer.displayInfo();
    }
</script>
Listing 2 - How to work with the JS instance (01_creating_class/Default.aspx)

I hope there is nothing complicated in Listing 2. I will just mention the function $get. This function comes from the MS AJAX JS library, and it behaves in the same way as document.getElementById(). The screen-shot of the precedent example is on Figure 2.

Figure 2 - Creating class screen-shot

Figure 2 - Creating the class screenshot

OOP extensions - Creating an interface

Although I like OOP extensions, I have to say that I have never used interfaces in JavaScript. But it's good to introduce an example. Creating an interface is similar to creating a class. The only two differences are:

  • You are not doing the implementation of the interface, just putting throw Error.notImplemented(); in the implementation of the methods.
  • You call registerInterface instead of registerClass at the end of the script.

Let's look at the example in Listing 3.

Type.registerNamespace("DotNetSources.IComparable");

DotNetSources.IComparable = function() {
    throw Error.notImplemented();
}

DotNetSources.IComparable.prototype = {

    compare: function(value) {
        throw Error.notImplemented();
    }
}

DotNetSources.IComparable.registerInterface('DotNetSources.IComparable');
Listing 3 - Creating an interface (02_Interfaces/IComparable.js)

Implementing an interface is also very simple. Just create a class, and in the registerClass function, specify the interface. It is the third parameter of the function. The second parameter is the base class (I'll talk about inheritance in the next chapter). The class can implement many interfaces, thus you can write a list of interfaces separated by comma. Look at the following example for better understanding:

Type.registerNamespace("DotNetSources.Number");

DotNetSources.Number = function() {
    this._a = null;
}

DotNetSources.Number.prototype = {

    ///
    /// Implement the method compare from interface IComparable.
    ///
    compare: function(value) {
        return this._a > value._a;
    },

    // Properties

    get_a: function() {
        return this._a;
    },

    set_a: function(value) {
        this._a = value;
    }

}

DotNetSources.Number.registerClass('DotNetSources.Number', null, 
                                   DotNetSources.IComparable);
Listing 4 - Implementing interface (02_Interface/Number.js)

OOP extensions - Inheritance

Inheritance is much more interesting than interfaces. It plays an important role in creating AJAX controls. Because, in the case of AJAX controls, we will need to derive from JavaScript classes created in the MS AJAX JavaScript Library. But now, we will focus on the simple inheritance of two objects created by us. Look at the following UML class diagram for a visual presentation:

Figure 3 - Class diagram of JavaScript classes

Figure 3 - Class diagram of JavaScript classes

As you have probably noted, in this example, I'll cover how to override a method and how to call its base method as well. Let's discover how it looks in JavaScript code.

The Person class:

Type.registerNamespace("DotNetSources.Person");

// Ctor.
DotNetSources.Person = function() {
    // define class valiables
    this._name = null;
}

//
// Prototype
//
DotNetSources.Person.prototype = {

    //
    // Methods
    //
    toString: function() {
        return "Name: " + this.get_name();
    },

    displayInfo: function() {
        alert(this.toString());
    },

    //
    // Properties
    //
    get_name: function() {
        return this._name;
    },

    set_name: function(value) {
        this._name = value;
    }

}

DotNetSources.Person.registerClass('DotNetSources.Person');
Listing 5 - The Person class (03_Inheritance/Person.js)

We've already created a class in JavaScript, thus there aren't any surprises in Listing 5, and so, we can go on with the Customer class:

Type.registerNamespace("DotNetSources.Customer");

// Ctor.
DotNetSources.Customer = function() {

    DotNetSources.Customer.initializeBase(this);

    // define class valiables
    this._lastVisit = null;
}

//
// Prototype
//
DotNetSources.Customer.prototype = {

    //
    // Override method toString.
    //
    toString: function() {
        var b = DotNetSources.Customer.callBaseMethod(this, 'toString');
        return b + ", Last Visit: " + this.get_lastVisit();
    },

    //
    // Properties
    //
    get_lastVisit: function() {
        return this._lastVisit;
    },

    set_lastVisit: function(value) {
        this._lastVisit = value;
    }

}

DotNetSources.Customer.registerClass('DotNetSources.Customer', DotNetSources.Person);
Listing 6 - The Customer class (03_Inheritance/Customer.js)

The Customer class, on the other hand, contains new artifacts for us. Let's see these artifacts in detail:

  • In the constructor, call DotNetSources.Customer.initializeBase(this); in order to initialize the methods and properties of the base class. In our case, it is Person.
  • In the call registerClass at the end of the script, specify the derived class as the second parameter, like this: DotNetSources.Customer.registerClass('DotNetSources.Customer', DotNetSources.Person);.
  • When you override a method and want to call its base method, call callBaseMethod and specify the current instance and the name of the method as a string. Like the following: DotNetSources.Customer.callBaseMethod(this, 'toString');.

The Friend class:

Type.registerNamespace("DotNetSources.Friend");

// Ctor.
DotNetSources.Friend = function() {

    DotNetSources.Friend.initializeBase(this);

    // define class valiables
    this._dateOfBirth = null;
}

//
// Prototype
//
DotNetSources.Friend.prototype = {

    //
    // Override method toString.
    //
    toString: function() {
        var b = DotNetSources.Friend.callBaseMethod(this, 'toString');
        return b + ", Date of Birth:: " + this.get_dateOfBirth();
    },

    //
    // Properties
    //
    get_dateOfBirth: function() {
        return this._dateOfBirth;
    },

    set_dateOfBirth: function(value) {
        this._dateOfBirth = value;
    }

}

DotNetSources.Friend.registerClass('DotNetSources.Friend', DotNetSources.Person);
Listing 7 - The Friend class (03_Inheritance/Friend.js)

The classes introduced in Figure 3 have been created, and now it's time to use it. This is done by the script in Listing 8.

<asp:ScriptManager runat="server" ID="sManager">
    <Scripts>
        <asp:ScriptReference Path="~/03_Inheritance/Person.js" />
        <asp:ScriptReference Path="~/03_Inheritance/Customer.js" />
        <asp:ScriptReference Path="~/03_Inheritance/Friend.js" />
    </Scripts>
</asp:ScriptManager>
<div>
    Name: <input type="text" id="txtName" /><br />
    Date of Birth or Last Visit: <input type="text" id="txtDateOfBirth" /><br />
    <input type="button" 
       value="Create an instance of Customer and call 
              DisplayInfo method which is defined in Person class." 
       onclick="btnCustomer()" />
    <br />
    <input type="button" 
      value="Create an instance of Friend and call DisplayInfo 
             method which is defined in Person class." 
      onclick="btnFriend()" />
</div>
</form>
<script language="javascript" type="text/javascript">
    function btnCustomer() {
        // create instance
        var myCustomer = new DotNetSources.Customer();
        // set properties
        myCustomer.set_name($get('txtName').value);
        myCustomer.set_lastVisit($get('txtDateOfBirth').value);
        // call method on the instance of of Customer class
        myCustomer.displayInfo();
    }

    function btnFriend() {
        // create instance
        var myFriend = new DotNetSources.Friend();
        // set properties
        myFriend.set_name($get('txtName').value);
        myFriend.set_dateOfBirth($get('txtDateOfBirth').value);
        // call method on the instance of of Customer class
        myFriend.displayInfo();
    }
</script>
Listing 8 - Using classes from Figure 3 (03_Inheritance/Default.aspx)

I have got some screenshots for you. In Figure 4 is the result of the function btnCustomer() from Listing 8, and in Figure 5 is the result of the function btnFriend() from Listing 8.

Figure 4 - Creating Customer instance and calling displayInfo on it.

Figure 4 - Creating a Customer instance and calling displayInfo on it.

Figure 5 - Creating Friend instance and calling displayInfo on it.

Figure 5 - Creating Friend instance and calling displayInfo on it.

As you can see on the screenshots, both Figure 4 and Figure 5 provide different results although I'm calling the same method named displayInfo which is defined only on the Person class. The concrete implementations of the Person class (Customer and Friend) override the toString method and providing different strings.

OOP extensions - Enumerators

Although it is unbelievable, there are enumerators as well. I assume everyone knows what an enumerator is, so we can go directly to the example.

Type.registerNamespace('DotNetSources');

DotNetSources.Severity = function() {
    // nothing, just enumerator
}

//
// Severity enumerator.
//
DotNetSources.Severity.prototype = {
    Error: 1,
    Warning: 2,
    Info: 3
}

DotNetSources.Severity.registerEnum('DotNetSources.Severity');
Listing 9 - Severity enumerator (04_Enum/Severity.js)

Furthermore, an enumerator represents a number. For example, calling:

DotNetSources.Severity.Error

gives you the number 1. See the following screenshot based on the example from the download package (04_Enum/Default.aspx).

Figure 6 - The screen-shot of getting value of enumerator. The first button was pressed.

Figure 6 - The screenshot of getting the value of the enumerator. The first button was pressed.

ASP.NET AJAX client life-cycle events

Every example introduced in this article use the objects when clicking on a button. This is a quite safe state because everything is loaded and initialized. However, there could be a situation where you need to use the objects when the web page is requested. Obviously, you can't just put script tags everywhere and write some code working with the objects because you are not sure if the ScriptManager already did the initialization of the MS AJAX JS Library or not. In this situation, it is good to know something about the ASP.NET AJAX client life-cycle events. All the stages can be discovered on reference [3]. In this article, I show you how to work with pageLoad.

Let's stop talking, and see an example. I use the class Customer from Listing 1. When the page is requested, I create an instance of the Customer class and I call a method on it. See the following piece of code:

<asp:ScriptManager runat="server" ID="sManager">
    <Scripts>
        <asp:ScriptReference Path="~/01_creating_class/Customer.js" />
    </Scripts>
</asp:ScriptManager>
<div>
</div>
<script type="text/javascript">

    function pageLoad() {
        // create instance
        var myCustomer = new DotNetSources.Customer();
        // set properties
        myCustomer.set_name('Petr');
        myCustomer.set_dateOfBirth('02.02.1983');
        // call method on the instance of of Customer class
        myCustomer.displayInfo();
    }
</script>
Listing 11 - Working with objects when a page is loaded (06_PageLoad/Default.aspx)

As you can see in Listing 11, I have put my code into the pageLoad function. The pageLoad function is called automatically after the MS AJAX JS Library is initialized. Thus, you are sure you can make the instances of your classes.

Creating handlers in the context of the class

You probably know that via JavaScript you can register handlers for DOM elements. Consider a situation where you have a button in a page. Using JavaScript, you want to tell that when the user clicks on the button, an XX JavaScript function will be performed. Maybe you know how to do that in raw JavaScript, but in raw JavaScript, the implementation is different for each browser. MS AJAX JS Library is oriented towards you, and provides only one approach to add these handlers to DOM elements. The magic function is named $addHandler/$removeHandler, and the definition is:

$addHandler(element,"eventName", handler);
$removeHandler(element,"eventName", handler);
  • element - It is the DOM element. You can reach it using document.getElementById from raw JavaScript, or shortly using $get, which is the same as document.getElementById. I recommend you to use $get because $get is on the highest level of an abstraction.
  • eventName - is the string. It is the name of the event of the element from the first parameter. You can see the list of events for each element on reference [4]. Just click on the tag you are interested in and see the table "Event Attributes". The eventName here is without the "on" prefix. Thus, instead of onclick, you pass only click.
  • handler - is the name of the function in JavaScript. Basically, if you are working with simple functions in JavaScript and you are not using classes, you can pass here the name of the function. However, when you are working with classes and want to pass one of the methods of the class, then you have to create the handler using the Function.createDelegate function. It is good to keep the result of Function.createDelegate as one of the local variables of the class in order to be able to call $removeHandler on dispose or page unload.

Let's consider the following example:

Create a JavaScript class which takes two arguments: the ID of the text box and the ID of the DIV (I'm talking about the IDs of the elements in the DOM). The class itself will take care of the following functionality: When the user types a letter into the text box, the content of the text box will appear in the DIV, letter after letter. The HTML for such a page can look like:

<div>
    Type something here: <input type="text" id="txtInput" /><br /><br />
    You are typing: <div id="lblEcho"></div>
</div>
<script type="text/javascript">

    function pageLoad() {
        // create instance
        var status = new DotNetSources.StatusInfo('txtInput', 'lblEcho');
        // start sniffing
        status.sniff();
    }
</script>
Listing 10 - (05_Events/Default.aspx)

As you can see in Listing 10, there is a text box and a DIV. The JavaScript code has two lines:

var status = new DotNetSources.StatusInfo('txtInput', 'lblEcho');
status.sniff();

Here, you have the text box ID, the DIV ID, and can sniff what I'm writing into the text box. Now, it's time to look at the implementation of the DotNetSources.StatusInfo class.

Type.registerNamespace("DotNetSources.StatusInfo");

DotNetSources.StatusInfo = function(textBoxId, labelId) {

    // define class valiables
    this._textBoxId = textBoxId;
    this._labelId = labelId;

    // define delegates
    this._onkeyup = null;
    this._onDispose = null;
}

// 
// Prototype 
//
DotNetSources.StatusInfo.prototype = {

    //
    // Methods
    //
    sniff: function() {

        // get element
        var textBox = $get(this._textBoxId);

        // create delegates
        this._onkeyup = Function.createDelegate(this, this._keyup);
        this._onDispose = Function.createDelegate(this, this._dispose);

        // add handler to the text box
        $addHandler(textBox, 'keyup', this._onkeyup);

        // run dispose when page unload
        Sys.Application.add_unload(this._onDispose);

    },

    _keyup: function() {
        // get label element and set it to value from textBox
        $get(this._labelId).innerText = $get(this._textBoxId).value;
    },

    _dispose: function() {
        // clear handlers after your-self
        $removeHandler($get(this._textBoxId), 'keyup', this._onkeyup);
        Sys.Application.remove_unload(this._onDispose);
    }

}

DotNetSources.StatusInfo.registerClass('DotNetSources.StatusInfo');
Listing 11 - DotNetSources.StatusInfo class (05_Events/StatusInfo.js)

ASP.NET AJAX control

We went through the principles to work with classes created in the MS AJAX JS Library. In the following chapters, I'll write the basics about creating ASP.NET AJAX controls. If you read the precedent chapters of this article, it will be very easy for you to understand how the ASP.NET AJAX controls work.

ASP.NET AJAX control - Web Control

In this section, I will assume that you know how to create a Web Control in ASP.NET.

An ASP.NET AJAX control is nothing other than a simple Web Control which has a mirroring JavaScript class on the client side. When you are creating an ASP.NET AJAX control, you have to create a JavaScript class which derives from Sys.UI.Control and associate this JavaScript class with the control written in .NET (using C#, VB, etc.). Look at the following visual presentation:

Figure 7 - WebControl with JavaScript class

Figure 7 - WebControl with JavaScript class

I have also prepared the example for you. Consider the DIV element as a square with a red background. When you click on the DIV, the alert box with the message will be displayed. How do we reach this functionality using the ASP.NET AJAX control is shown in Listing 12 and Listing 13.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

[assembly: WebResource("DotNetSources_e0003._07_Web_Control.RedSquare.js", 
                       "text/javascript", PerformSubstitution = true)]

namespace DotNetSources_e0003
{

    public class RedSquare : WebControl, IScriptControl
    {
        public RedSquare()
            : base(HtmlTextWriterTag.Div)
        {
        }

        ScriptManager sm;

        protected override void OnPreRender(EventArgs e)
        {
            this.Style.Add(HtmlTextWriterStyle.BackgroundColor, "Red");
            this.Width = this.Height = 200;

            if (!this.DesignMode)
            {
                sm = ScriptManager.GetCurrent(Page);
                sm.RegisterScriptControl(this);
            }
            base.OnPreRender(e);
        }

        /// <summary>
        /// 
        /// <summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer)
        {
            if (!this.DesignMode)
            {
                sm.RegisterScriptDescriptors(this);
            }
            base.Render(writer);
        }


        public IEnumerable<System.Web.UI.ScriptDescriptor> GetScriptDescriptors()
        {
            ScriptControlDescriptor descriptor = 
               new ScriptControlDescriptor("DotNetSources.RedSquare", this.ClientID);
            return new ScriptDescriptor[] { descriptor };
        }

        public IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
        {
            ScriptReference jsReference = new ScriptReference();
            jsReference.Assembly = "DotNetSources_e0003";
            jsReference.Name = "DotNetSources_e0003._07_Web_Control.RedSquare.js";
            return new ScriptReference[] { jsReference };
        }

    }
}
Listing 12 - The RedSquare class; C# class (07_Web_Control/RedSquare.cs)
Type.registerNamespace("DotNetSources.RedSquare");

DotNetSources.RedSquare = function(element) {
    DotNetSources.RedSquare.initializeBase(this, [element]);

    // handlers
    this._onClickHandler = null;
}

DotNetSources.RedSquare.prototype = {

    initialize: function() {
        DotNetSources.RedSquare.callBaseMethod(this, 'initialize');
        this._onClickHandler = Function.createDelegate(this, this.onClick);
        $addHandler(this.get_element(), "click", this._onClickHandler);
    },

    onClick: function() {
        alert('You clicked on the red square.');
    },

    dispose: function() {
        //Add custom dispose actions here
        $clearHandlers(this.get_element());
        DotNetSources.RedSquare.callBaseMethod(this, 'dispose');
    }
}
DotNetSources.RedSquare.registerClass('DotNetSources.RedSquare', Sys.UI.Control);
Listing 13 - The RedSquare class, JavaScript class (07_Web_Control/RedSquare.js)

I didn't mention how precisely the JavaScript class and the WebControl class are connected, but I guess you noted the IScriptControl interface. There are two methods on the IScriptControl interface used to connect the control with the JavaScript resource. If you want to know more about IScriptControl, you can follow reference [5].

ASP.NET AJAX control - User Control

Many people like to build User Controls (template controls) instead of Web Controls. The JavaScript class in this case is a little bit different. Basically, the User Control has no root element; therefore, you can't derive the JavaScript class from Sys.UI.Control. However you can derive it from Sys.Component. If you want to see a visual representation, you can look at Figure 7 and imagine Sys.Component instead of Sys.UI.Control and System.UI.UserControl instead of System.UI.Web.WebControls.WebControl.

Also, in this chapter, I have prepared an example for you. In this example, I added the handover values between the server control and the JavaScript class. Please notice the GetScriptDescriptors method in Listing 14 to see how to pass values from the server control to the JavaScript class.

[assembly: WebResource("DotNetSources_e0003._08_User_Control.TableOfFourColors.js", 
   "text/javascript", PerformSubstitution = true)]

namespace DotNetSources_e0003._08_User_Control
{
    public partial class TableOfFourColors : UserControl, IScriptControl
    {

        protected void Page_Load(object sender, EventArgs e)
        {
        }

        ScriptManager sm;

        protected override void OnPreRender(EventArgs e)
        {

            if (!this.DesignMode)
            {
                sm = ScriptManager.GetCurrent(Page);
                sm.RegisterScriptControl(this);
            }
            base.OnPreRender(e);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer)
        {
            if (!this.DesignMode)
            {
                sm.RegisterScriptDescriptors(this);
            }
            base.Render(writer);
        }

        public IEnumerable<System.Web.UI.ScriptDescriptor> 
               GetScriptDescriptors()
        {
            ScriptControlDescriptor descriptor = 
              new ScriptControlDescriptor(
              "DotNetSources.TableOfFourColors", this.ClientID);
            descriptor.AddProperty("pnlRed", pnlRed.ClientID);
            descriptor.AddProperty("pnlBlue", pnlBlue.ClientID);
            descriptor.AddProperty("pnlYellow", pnlYellow.ClientID);
            descriptor.AddProperty("pnlGreen", pnlGreen.ClientID);
            return new ScriptDescriptor[] { descriptor };
        }

        public IEnumerable<System.Web.UI.ScriptReference> 
               GetScriptReferences()
        {
            ScriptReference jsReference = new ScriptReference();
            jsReference.Assembly = "DotNetSources_e0003";
            jsReference.Name = "DotNetSources_e0003." + 
                               "_08_User_Control.TableOfFourColors.js";
            return new ScriptReference[] { jsReference };
        }
    }
}
Listing 14 - The TableofFourColors class, C# class - (08_User_Control/TableOfFourColors.ascx.cs)
Type.registerNamespace("DotNetSources.TableOfFourColors");

DotNetSources.TableOfFourColors = function() {
    DotNetSources.TableOfFourColors.initializeBase(this);

    // handlers
    this._onClickHandlerRed = null;
    this._onClickHandlerBlue = null;
    this._onClickHandlerYellow = null;
    this._onClickHandlerGreen = null;

    // properties
    this._pnlRed = null;
    this._pnlBlue = null;
    this._pnlYellow = null;
    this._pnlGreen = null;
}

DotNetSources.TableOfFourColors.prototype = {

    initialize: function() {
        DotNetSources.TableOfFourColors.callBaseMethod(this, 'initialize');

        // create delegates
        this._onClickHandlerRed = 
             Function.createDelegate(this, this.onClickRed);
        this._onClickHandlerBlue = 
             Function.createDelegate(this, this.onClickBlue);
        this._onClickHandlerYellow = 
             Function.createDelegate(this, this.onClickYellow);
        this._onClickHandlerGreen = 
             Function.createDelegate(this, this.onClickGreen);

        // add handlers
        $addHandler($get(this.get_pnlRed()), 
                    "click", this._onClickHandlerRed);
        $addHandler($get(this.get_pnlBlue()), 
                    "click", this._onClickHandlerBlue);
        $addHandler($get(this.get_pnlYellow()), 
                    "click", this._onClickHandlerYellow);
        $addHandler($get(this.get_pnlGreen()), 
                    "click", this._onClickHandlerGreen);
    },

    onClickRed: function() {
        alert('You clicked on the red part.');
    },

    onClickBlue: function() {
        alert('You clicked on the blue part.');
    },

    onClickYellow: function() {
        alert('You clicked on the yellow part.');
    },

    onClickGreen: function() {
        alert('You clicked on the green part.');
    },

    // properties

    get_pnlRed: function() {
        return this._pnlRed;
    },

    set_pnlRed: function(value) {
        this._pnlRed = value;
    },

    get_pnlBlue: function() {
        return this._pnlBlue;
    },

    set_pnlBlue: function(value) {
        this._pnlBlue = value;
    },

    get_pnlYellow: function() {
        return this._pnlYellow;
    },

    set_pnlYellow: function(value) {
        this._pnlYellow = value;
    },

    get_pnlGreen: function() {
        return this._pnlGreen;
    },

    set_pnlGreen: function(value) {
        this._pnlGreen = value;
    },

    // dispose
    dispose: function() {
        //Add custom dispose actions here
        $clearHandlers($get(this.get_pnlRed()));
        $clearHandlers($get(this.get_pnlBlue()));
        $clearHandlers($get(this.get_pnlYellow()));
        $clearHandlers($get(this.get_pnlGreen()));
        DotNetSources.TableOfFourColors.callBaseMethod(this, 'dispose');
    }
}
DotNetSources.TableOfFourColors.registerClass(
        'DotNetSources.TableOfFourColors', Sys.Component);
Listing 15 - The TableofFourColors class, JavaScript class - (08_User_Control/TableOfFourColors.js)

Conclusion

Thank you for reading. I hope it was useful for you. As usual, I'm interested in feedback, so don't hesitate to write a comment or vote. Thank you very much.

References

History

  • 29 January 2010 - Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here