Welcome to AspAdvice Sign in | Join | Help

Alessandro Gallo

.NET & Beyond
MS AJAX: A helper for creating component events

Introduction

Microsoft Ajax defines a component as a class that inherits from the base Sys.Component class. Components are able to raise events thanks to a pattern similar to the one in .NET framework. Let's see how we can expose an event with a single line of JavaScript.

Component events and DOM events

We must not confuse events raised by DOM elements with events raised by MS AJAX components. To attach an event handler to a DOM element, we can use the $addHandler and $removeHandler shortcuts, that provide a cross-browser interface to deal with events raised by DOM elements.

The new beta2 release adds two nice helpers for rapidly attaching and detaching handlers to/from a DOM element. The first one, $addHandlers(), allows to add handlers to multiple events with a single statement, and takes care of creating the corresponding delegates. The second one, $clearHandlers(), detaches all the handlers attached with $addHandlers and disposes the corresponding delegates. Please check this blog entry by Bertrand LeRoy for the details.

Component events

If we want to expose an event in a component, we have to:

  • Declare a method to add an event handler: add_someEvent() where someEvent is the name of the event that we want to create.
  • Declare a method to remove an event handler: remove_someEvent().
  • Declare a method that raises the event: raiseSomeEvent().

The above steps must be followed for each event we are going to create. Actually the third step could be simplified by declaring a method that raises a generic event, given the event name and the event arguments:

 

myComponent.prototype._raiseEvent = function(eventName, eventArgs)
{    
    var handler = this.get_events().getHandler(eventName);    
    
    if (handler) {    
        if (!eventArgs) {        
            eventArgs = Sys.EventArgs.Empty;    
        }    
        handler(this, eventArgs);    
    }
}

 

At this point, we have to declare only the methods for adding and removing an handler, and then call _raiseEvent with the name of the event. The following is the code needed to expose a dummyEvent:

 

MyComponent.prototype.add_dummyEvent = function(handler)
{    
    this.get_events().addHandler('dummyEvent', handler);
}
MyComponent.prototype.remove_dummyEvent : function(handler)
{    
    this.get_events().removeHandler('dummyEvent', handler);
}

 

Even with the help of _raiseEvent(), exposing a component event is a bit verbose in terms of code written.

The createEvent helper

The following code defines a createEvent helper that:

  • Adds the corresponding add_ and remove_ methods for adding and removing an event handler, given the name of the event.
  • The first time an instance of a particular class is created, it adds to the class a Sys.EventHandlerList collection used to hold event handlers, the get_events() method to retrieve the collection and the _raiseEvent method to raise an event.
  • Allows to expose events from every class and not only from components.

Here is the code:

 

Type.prototype.createEvent = function(eventName)
{    
    var addHandler = function(handler) {
        this.get_events().addHandler(eventName, handler);
    }
    
    var removeHandler = function(handler) {
        this.get_events().removeHandler(eventName, handler);
    }
    
    this.prototype['add_' + eventName] = addHandler;
    this.prototype['remove_' + eventName] = removeHandler;        
    
    addHandler = removeHandler = null;
    
    if(!this.__regEvents) {    
        if(!this.inheritsFrom(Sys.Component)) {        
            this.prototype.get_events = function() {            
                if (!this._events) {                
                    this._events = new Sys.EventHandlerList();            
                }            
                
                return this._events;        
             }
         }            
        
         this.prototype._raiseEvent = function(eventName, eventArgs) {            
            var handler = this.get_events().getHandler(eventName);                            
            
            if (handler) {                    
                if (!eventArgs) {                            
                    eventArgs = Sys.EventArgs.Empty;                    
                }                    
                
                handler(this, eventArgs);                
            }        
         }                
        
         this.__regEvents = true;    
    }
}

 

As you can see, we are extending Type (that is an alias for Function in the MS AJAX core library) with the createEvent method. The method is added to the prototype object; therefore, we must call the method from inside a class' constructor.

What the method does is creating the two functions for adding and removing an handler, and then adding them to the prototype object of the class. Notice how we are able to use the eventName parameter even inside the two child functions. This is possible thanks to the concept of closure. A closure is a child function that is able to access the context of the parent function. Note also that we are disposing the two closures after having used them.

Example

With the createEvent helper, this is the code necessary to expose a dummyEvent:

 

Type.registerNamespace('Samples');
Samples.MyClass = function() {    
    Samples.MyClass.createEvent('dummyEvent');
}
Samples.MyClass.registerClass('Samples.MyClass');

 

To raise the event, we just have to call _raiseEvent:

 

this._raiseEvent('dummyEvent');

 

Conclusion

The createEvent helper allows to expose a MS AJAX event in every class with a single JavaScript statement. A little overhead added by this approach is that the first instance of a class is responsible for adding the get_events() and _raiseEvent() methods to the prototype object of the class.

Posted: Thursday, November 09, 2006 3:03 PM by Garbin

Comments

Bertrand said:

Nice!

# November 9, 2006 12:39 PM

consumer said:

What would a consumer of this event look like?

# November 9, 2006 3:54 PM

LA.NET [EN] said:

Garbin has another great tip on his blog. He has just publish an event helper which cuts down the necessary

# November 9, 2006 5:52 PM

Christopher Steen said:

EJ: Essential JavaScript The Library [Via: Dion Almaer ] Apache Axis2 1.1 Released [Via: Anil John ]...

# November 14, 2006 11:11 PM

steve said:

Nice components. Have been looking for this.

http://ajax.techboo.com/archive/2006/11/20/6.aspx

# November 21, 2006 12:44 AM

Brian said:

How do you subscribe to the custom event?

# May 17, 2007 6:52 PM

Garbin said:

Brian: you would subscribe the event in the same way as with events exposed in the "regular" way. Thus, if you created a myEvent event using the helper, you can subscribe to it by calling the add_myEvent method, passing the event handler as an arugment.

# May 18, 2007 7:45 AM
New Comments to this post are disabled