Ext


Go Back   Ext JS Forums > Ext JS Community Forums (1.x) [Unsupported] > Ext 1.x: Help

Reply
 
Thread Tools
  #1  
Old 05-23-2007, 05:31 PM
BorisNikolaevich BorisNikolaevich is offline
Ext User
 
Join Date: Mar 2007
Posts: 3
BorisNikolaevich is on a distinguished road
Default How to implement Events which are not bound to Elements

There is just one thing that keeps me from being able to wipe out all my references to YAHOO.util.CustomEvent, and that is that I can't figure out from the Ext reference how to create & fire events that are not tied to Elements. Everything I can find on EventObject and EventManager and Observable seems to be focused on "user-object interaction events" (e.g. "click" an object) and not "application-UI interaction."

Let me give a description of what I mean, and then hopefully someone can say, "Boris, you дурак, it's simple to implement that using Ext as ________________, which you would know if you had read the documentation more carefully."

My application uses "message queues" based on YAHOO.util.CustomEvent to keep application components notified of state changes. For example, when a response from the server indicates that the "Current Organization" has changed, the response handler adds a "Current Organization Changed" message (i.e. event) to the application message queue. It does not keep track of which components need to know when the current organization has changed. Instead, any component which needs to perform some action when the current organization changes--maybe change the text in a panel, or enable certain buttons, whatever--subscribes to the application message queue and listens for "Current Organization Changed" messages.

Currently, the MessageQueue has two methods, sendMessage(queueName, message) and subscribe(queueName, messageHandler). A snippet from the sendMessage method:
if (!queueName) return false;
if(!queues[queueName])
{
	queues[queueName] = new YAHOO.util.CustomEvent(queueName, this);
}
message.queueName = queueName;
queues[queueName].fire(message);

("this" being the MessageQueue object which exposes the sendMessage method)
... and then, in the subscribe method, since queues[queueName] is a YAHOO.util.CustomEvent object, I can simply pass the subscription request on as
queues[queueName].subscribe(messageHandler)
For the "Current Organization Changed" example above, then, the method handling server responses might detect that the current organization has changed, and call
MessageQueue.sendMessage("Application Events", "Current Organization Changed")
and the component which needs to know about the change might add a line to its init() method like
MessageQueue.subscribe("Application Events", currentOrganizationChanged)
Note that all of this code is simplified for the purpose of illustration, and clearly there are some pieces I left out, but I wanted to make sure that the general concept was clear instead of focusing on the actual code. Can anyone tell me how to accomplish this by replacing YAHOO.util.CustomEvent(queueName, this) with Ext event objects? Thanks a million!
Reply With Quote
  #2  
Old 05-23-2007, 05:36 PM
tryanDLS tryanDLS is offline
Ext JS - Community Support Team
 
Join Date: Mar 2007
Posts: 7,411
tryanDLS is on a distinguished road
Default

Just thinking off the top of my head, but this might give you some direction. You can derive your object from Observable and add any events you want - they don't have to be UI related. You could look at Store as an example - it defines load and beforeload events that can be fired by code.
__________________
Tim Ryan - Ext JS Support Team
Read BEFORE posting a question / BEFORE posting a Bug
Use Google to Search - API / Forum
API Doc (3.x | 2.x | 1.x) / FAQ / Wiki / Tutorials / 1.x->2.0 Migration Guide
Reply With Quote
  #3  
Old 05-23-2007, 05:56 PM
BorisNikolaevich BorisNikolaevich is offline
Ext User
 
Join Date: Mar 2007
Posts: 3
BorisNikolaevich is on a distinguished road
Default

That's a great place to start, thanks for pointing me there, Tim. And just to be clear, it sounds like you're suggesting that the internal queues[queueName] object is the one that would derive from Observable, right? Something like the air code
queues[queueName] = new function {...}

Ext.extend(queues[queueName], Ext.util.Observable);
Of course, this also begs the question, "If I am using YUI as the base library for Ext, does it really matter if I replace CustomEvent?" Mostly I was doing this because Jack mentioned the performance improvement from removing CustomEvent from legacy code... and I am your run-of-the-mill follower.
Reply With Quote
  #4  
Old 05-23-2007, 06:42 PM
tryanDLS tryanDLS is offline
Ext JS - Community Support Team
 
Join Date: Mar 2007
Posts: 7,411
tryanDLS is on a distinguished road
Default

You'd probably want to kick it around a little as to whether individual queue elements are derived from Observable, or the queue itself does. In that case a queue might just contain a MixedCollection of it's objects. Kind of depends on whether the queue can delegate the events to the right object, or the objects have to do things themselves. The less events you have to create the better of you'll be performance wise

Going the Observable route means you get to use same syntax as the rest of Ext and don't have to code to the YAHOO API, and if you ever need to switch adapters, it's transparent.
__________________
Tim Ryan - Ext JS Support Team
Read BEFORE posting a question / BEFORE posting a Bug
Use Google to Search - API / Forum
API Doc (3.x | 2.x | 1.x) / FAQ / Wiki / Tutorials / 1.x->2.0 Migration Guide
Reply With Quote
  #5  
Old 05-26-2007, 04:40 AM
BorisNikolaevich BorisNikolaevich is offline
Ext User
 
Join Date: Mar 2007
Posts: 3
BorisNikolaevich is on a distinguished road
Default

Thanks again, Tim. I did play with both an Observable MessageQueue manager object and Observable queues. With the Observable MessageQueue, the queue name becomes the event name, and so broadcasting a message means calling this.fireEvent(queueName, message) to notify all subscribers. In this case, the global MessageQueue can be defined like this:
examplenamespace.MessageQueue = function()
{
	var _messageQueue = function()
	{
		this.SendMessage = function(message, queueName)
		{
			// optional queueName parameter allows easy re-sending
			// of a message on a different queue, overriding the
			// original queue.
			if (queueName) 
			{
				message.queueName = queueName;
			}
			else
			{
				queueName = message.queueName;
			}
			if (!queueName) return false;
			var queue = {events: {}};
			queue.events[queueName] = true;
			this.addEvents(queue);
			
			this.fireEvent(queueName, message);
			
			return true;
		}
		
		this.Subscribe = function(subscription, callback, subscriberArgs)
		{
			var subscriptionInfo = {};		
			
			// The subscription can be created by passing an object with
			// subscription properties, or can be created with a shortcut
			// in the form of "Query Name:Message Name:Message Content"
			// (where Message Name and Message Content are both optional)
			if (typeof(subscription)=='string')
			{
				subscription = subscription.split(':');
				subscriptionInfo.queueName = subscription[0];
				subscriptionInfo.name = subscription[1];
				subscriptionInfo.content = subscription[2];
			}
			else
			{
				subscriptionInfo = subscription;
			}
			subscriptionInfo.subscriberArgs = subscriberArgs;
			
			var queueName = subscriptionInfo.queueName;
			
			if (!queueName || !callback) return false;
			var queue = {events: {}};
			queue.events[queueName] = true;
			this.addEvents(queue);

			this.on
				(
					queueName,
					function(message, subscriptionInfo)
					{
						
						// A subscriber can listen to the whole message queue, or
						// to messages on the queue with specific properties.
						// Here we look at the subscription properties to see
						// whether the message matches the subscription.
						var subscriptionMatched = true;
						for (var filterItem in subscriptionInfo)
						{
							if(subscriptionInfo[filterItem] && (filterItem != 'subscriberArgs'))
							{
								subscriptionMatched = (subscriptionMatched && (subscriptionInfo[filterItem] == message[filterItem]));
								if (!subscriptionMatched) break;
							}
						}
						if (subscriptionMatched) 
						{
							callback(message, subscriptionInfo.subscriberArgs);
						}
					}.createDelegate(this, subscriptionInfo, true)											
				)
		}
	}
	
	Ext.extend(_messageQueue, Ext.util.Observable);
	
	return new _messageQueue();
}();
On the other hand, if it is not the MessageQueue but the internal queues themselves which are Observable, only the guts of the MessageQueue object need to change:
examplenamespace.MessageQueue = function()
{
	var queues = {};
	
	messageQueue = function(queueName)
	{
		this.name = queueName;
		this.events = {"MessageSent": true};	
	}
	
	Ext.extend(messageQueue, Ext.util.Observable);
	
	return {
		SendMessage: function(message, queueName)
		{
			// optional queueName parameter allows easy re-sending
			// of a message on a different queue, overriding the
			// original queue.
			if (queueName) 
			{
				message.queueName = queueName;
			}
			else
			{
				queueName = message.queueName;
			}
			if (!queueName) return false;
			if(!queues[queueName])
			{
				queues[queueName] = new messageQueue(queueName);
			}
			
			queues[queueName].fireEvent("MessageSent", message);
			
			return true;
		}
		,
		Subscribe: function(subscription, callback, subscriberArgs)
		{
			var subscriptionInfo = {};		
			
			// The subscription can be created by passing an object with
			// subscription properties, or can be created with a shortcut
			// in the form of "Query Name:Message Name:Message Content"
			// (where Message Name and Message Content are both optional)
			if (typeof(subscription)=='string')
			{
				subscription = subscription.split(':');
				subscriptionInfo.queueName = subscription[0];
				subscriptionInfo.name = subscription[1];
				subscriptionInfo.content = subscription[2];
			}
			else
			{
				subscriptionInfo = subscription;
			}
			subscriptionInfo.subscriberArgs = subscriberArgs;
			
			var queueName = subscriptionInfo.queueName;
			
			if (!queueName || !callback) return false;

			if(!queues[queueName])
			{
				queues[queueName] = new messageQueue(queueName);
			}

			queues[queueName].on
				(
					"MessageSent",
					function(message, subscriptionInfo)
					{
						
						// A subscriber can listen to the whole message queue, or
						// to messages on the queue with specific properties.
						// Here we look at the subscription properties to see
						// whether the message matches the subscription.
						var subscriptionMatched = true;
						for (var filterItem in subscriptionInfo)
						{
							if(subscriptionInfo[filterItem] && (filterItem != 'subscriberArgs'))
							{
								subscriptionMatched = (subscriptionMatched && (subscriptionInfo[filterItem] == message[filterItem]));
								if (!subscriptionMatched) break;
							}
						}
						if (subscriptionMatched) 
						{
							callback(message, subscriptionInfo.subscriberArgs);
						}
					}.createDelegate(this, subscriptionInfo, true)											
				)
		}
	}
}();
I actually went with the second technique, both because I found it easier to follow the concept when trying to look at it as "what if I weren't the guy who wrote this?" and because I couldn't find a way I liked for adding a dynamic event property to pass to addEvents. The statement
| var queue = {events: {}};
| queue.events[queueName] = true;

looks too... um, hacked, which it is.

Looking at the internals of EventManager, I think I could also have made that work for me instead of a MessageQueue; however, updating the MessageQueue meant fewer changes to the rest of the application's code. And since I very much believe in sharing the pieces I can, I wanted to post these two examples in case someone else is using a similar design pattern. To make the code complete, for either version of the MessageQueue I've got a Message class
examplenamespace.MessageQueue.Message = function(queueName, messageName, messageContent, messageSource)
{
	this.queueName = queueName;
	this.name = messageName;
	this.content = messageContent;
	this.source = messageSource;
};
... two very simple examples of "subscriptions" which might be defined in some components' init() method
examplenamespace.MessageQueue.Subscribe
(
	"Application Events", 
	function(message)
	{
		alert("An application event occured")
	}
);

examplenamespace.MessageQueue.Subscribe
(
	"Application Events:Organization Changed", 
	function(message, args)
	{
		alert(message.name + " changed to " + message.content + " by " + args)
	},
	"Joe Schmoe"
);
... and an example of sending a message, which might happen in a data processing routine or even in another UI component:
MessageQueue.SendMessage
(
	new MessageQueue.Message("Application Events", "Organization Changed", 1097, this)
)
I'd love to hear any feedback from anyone who is using something similar, or who learns something useful from my post. Otherwise, Enjoy!

P.S. I know that there's no Unsubscribe method... so far, there hasn't been a need for one in this project. You may find that you need to write one.
Reply With Quote
  #6  
Old 07-04-2007, 05:57 PM
rushedlogic rushedlogic is offline
Ext User
 
Join Date: Jul 2007
Posts: 2
rushedlogic is on a distinguished road
Default

This is just the topic i needed to discuss...

I'm looking to create a message queue so i can produce a UI of loosely coupled components. These eventing topics are pretty standard in a Swing type application and I'd like to apply the same good practices to my apps in Ext.

My key obective is to have a central global event loop that components can attach themselves to and broker all global activity.

BorisNikolaevich - Are my objectives anything like yours with this thread? If so, have you found a neat way to get IFrames to communicate neatly?


I wish i had found this thread before i created one just yesterday
Reply With Quote
  #7  
Old 04-13-2008, 10:46 AM
vmorale4's Avatar
vmorale4 vmorale4 is offline
Ext User
 
Join Date: Mar 2007
Location: Chicago, IL
Posts: 187
vmorale4 is on a distinguished road
Default

I'm so glad I found this post!

Just my 2 cents, but it would be nice if this pattern of element-agnostic message queues was built-in in Ext 2.x core, it helps avoid unnecessary coupling. It is specially useful for large, dynamic apps where the components that are going to be load is not necessary known,or new components are deleted/updated frequently.
Reply With Quote
  #8  
Old 04-13-2008, 07:04 PM
hendricd's Avatar
hendricd hendricd is offline
Ext JS - Development Team
 
Join Date: Aug 2007
Location: Long Island, NY USA
Posts: 5,356
hendricd is on a distinguished road
Send a message via AIM to hendricd Send a message via MSN to hendricd Send a message via Yahoo to hendricd Send a message via Skype™ to hendricd
Default

Quote:
If so, have you found a neat way to get IFrames to communicate neatly?
Have a look at ManagedIFrame (sig below), it has a x-frame messaging system (messaging for same-origin domains only) which may be of interest.

It exposes frame messaging via standard Ext Events.
Reply With Quote
  #9  
Old 06-15-2009, 09:05 AM
anshubansal2000 anshubansal2000 is offline
Ext User
 
Join Date: Jan 2009
Posts: 100
anshubansal2000 is on a distinguished road
Default

Hi Guys,
I saw the discussion is around implementing custom events. I am also having hard time in implementing some custom event on GridPanel. I noticed that there is NO OnRowOver and OnRowOut functionality attached to the Grid Panel so I thought to implement on my own but am without luck.

Here is the things I implemented.
I declared a GridPanel just a basic one.

Now I am initializing yahoo's custom events just like this. and attaching it to the grid.


//EVent Declaration:

onRowChange = new YAHOO.util.CustomEvent("onRowChange");
onRowChange.subscribe(testing);

//Grid Attachment.

grid.on('onRowChange',this);

//Testing Function:
function testing()
{
    
alert('Hi I am in Row Select');


But this doesn't seem to be working. Am I doing something wrong? Can we attach any custom event to ext's component like this??

Help and replies are appreciated.

Thanks
Anshu
Reply With Quote
Reply

Thread Tools

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

All times are GMT -5. The time now is 11:23 AM.

© 2006-2009 Ext, LLC
Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.