PDA

View Full Version : Application Event (Message) Bus



mjack003
26 Nov 2008, 10:54 AM
Howdy,

I'm still a "noob" to Ext and javascript for that matter but have been involved with application design and architecture for quite some time. Everything I've used in this library has been very OO oriented and clean and has been an incredible help in a large application that I'm developing up until this point. After hours of searching through pages of API docs and forum posts I still have not been able to find a good example of loose coupling between UI components. Saki has many great posts and examples of cross component event communication but to me this still is not loosely coupled as some parent component must know about the two components and make the connection. Well what if the parent does not exist or one of the child components has not been rendered yet or why is the parent component needed at all if only to connect the two components? I'd like to mirror the loose coupling of our server side SOA architecture and use custom events as "messages" between components with a global "message" (event) bus. The idea is when a component is initialized, it adds its cross component listeners to the bus and as certain components fire off custom events, they are fired internally which is usually not needed as a method call is more appropriate and then fired in the global bus where components that have subscribed to that event can then act on it without ANY other component ever needing to know the other exists. I have yet to find an example of this setup.

After rambling on, I'm sure there are others out there that have faced this problem so please post your ideas and suggestions as to the easiest way to accomplish this.

Best Regards,
Mjack

ThorstenSuckow
26 Nov 2008, 11:05 AM
Use the force, use the search ;)

There are already a few different implementations out there:

http://www.extjs.com/forum/showthread.php?t=42942&highlight=messagebus

HTH

Thorsten

EDIT:
Loose coupling ftw!

Sorry, I just had to add this...

mjack003
26 Nov 2008, 11:30 AM
Nice Thorsten. Thanks for the link and quick reply...don't know how I missed it...considering "messagebus" is in the title. This is a base to start from. Any easy way to integrate this into the observable class with an override? Mainly for fireEvent, so that any fireEvent will fire on the local component and then in the global bus? This will cut down on code length and the need to continually hard code the message bus object into components.

And yes....loose coupling ftw! Couldn't dream of a world without it. Loosely coupled server side and UI...couldn't ask for anything more.

Mjack

jack.slocum
26 Nov 2008, 11:35 AM
http://extjs.com/forum/showthread.php?p=240305#post240305

mjack003
26 Nov 2008, 11:58 AM
Jack,

Thanks for the link. That post is actually what lead me in the right direction as far as setting up a global observable.
I set up a single global observable where my components can add listeners but my question is how to then fire an event without having to hard code that global observable into each component? Instead it would be much easier to be able to use myComponent.fireEvent('myCustomEvent') and have this fire on myComponent and in the global bus. By practice I use one bus per one app for simplicity and centralization so its always going to be the same global object for inter component communication. Maybe I'm misunderstanding how to use observables correctly.

Mjack

mjack003
26 Nov 2008, 3:16 PM
After doing some more reading, is there a safe way to override the observables class' fireEvent method to trigger the event on the component (current action) and then pass that event to the global observable so that in effect all components that extend the observable class will fire events in both places? I would rather not hard code my global bus into what will become 200+ pre-configured classes. Appreciate any input.

Regards,
Mjack

evant
26 Nov 2008, 3:30 PM
You could, but then it's not really the observable pattern any more. Surely you don't need every event for every observable to pass through a single point?

mjack003
26 Nov 2008, 4:32 PM
Your right I wouldn't want every event to pass through a single point but that's what I'm trying to determine without reinventing the wheel that the Ext devel team has so carefully polished. What is the best approach to publishing specific custom events to a global observable without having to use something like the following:

myComponent.fireEvent('customEvent');
myApp.messageBus.fireEvent('customEvent');

It would be ideal to initialize and set the global bus in one location, which I have done. And then extend the observable class to accept an extra parameter in the fireEvent method that would determine whether to pass this event on to the global bus for inter component communication, giving true loose coupling. Also, would be ideal to reference the global observable in the observable class so hardcoding is minimal.

Components subscribe to events in one central location and publish to one central location without any coupling to any other component except for the event name and the global observable does not have to subscribe to component events, rather they "push" the events.

Question is....how would someone accomplish this with Ext?

Mjack

jack.slocum
26 Nov 2008, 4:54 PM
What I would recommend doing is defining the events you would like to have at the application level. In the post I linked to above, I had login and sessionexpired events as examples. The assumption is that for application scope events, you want a behavior to occurs which is more than (or at least different) than the default Ext behavior.

So say, for example you have a tree on the left of your application that provides navigation through your application. You could, as you described above, just fire the selectionchange event of the TreeSelectionModel through the central observable.

But is that really what you want?


MyApp.on('selectionchange', function(sm, selection){
if(sm.tree.id == 'my-navigation-tree' && selection){
// do something with selection.attributes.action
}
});

With that code, you have successfully removed the need to have a reference to the tree or selection model, but the dependency on the tree and selection model is still there.

The way I do it is to instead encapsulate the firing of the event to the bus.


// standard method of extending the tree
MyApp.Navigator = Ext.extend(Ext.tree.TreePanel, {
initComponent: function(){
// configure tree, call superclass, etc
...
this.getSelectionModel().on('selectionchange', this.onNavigate, this);
},

onNavigate: function(sm, selection){
if(selection){
MyApp.fireEvent('navigate', {
action: selection.attributes.action
});
}
}
});

Your listener now looks like this:

MyApp.on('navigate', function(e){
// do something with e.action
});

See now how your listener is now completely decoupled from the tree or any implementation details at all? This is cool because now when you implement another method of navigating, your existing listener can handle it just fine.

For example:


Ext.History.on('change', function(token){
MyApp.fireEvent('navigate', {
action: token
});
});

mjack003
26 Nov 2008, 9:11 PM
The way I do it is to instead encapsulate the firing of the event to the bus.


// standard method of extending the tree
MyApp.Navigator = Ext.extend(Ext.tree.TreePanel, {
initComponent: function(){
// configure tree, call superclass, etc
...
this.getSelectionModel().on('selectionchange', this.onNavigate, this);
},

onNavigate: function(sm, selection){
if(selection){
MyApp.fireEvent('navigate', {
action: selection.attributes.action
});
}
}
});

Thanks for the example and time Jack. That's a huge help. I took your example and came up with something similar except that the bus knows nothing about the listner functions (I

mjack003
30 Nov 2008, 2:11 PM
Hope everyone had a safe and enjoyable holiday weekend. I haven't had much time to code or research but due to the silence and lack of arguments against my previous post I'm going to push forward with developing my classes and message bus based on Jack's example with a minor twist. I did catch a post in the few minutes of reading I had over the weekend that the devel team is planning on adding a "pagebus"? I was just curious how solidified these plans are and what is the planned release date and functionality? Would be nice to see it fully integrated into the existing library to cut down on code length.

Mjack

jack.slocum
1 Dec 2008, 2:51 PM
Just FYI, if you really wanted to fire all events on a page level Observable, you could always put this code somewhere:


Ext.util.Observable.capture(Ext.util.Observable.prototype, function(){
YourBus.fireEvent.apply(YourBus, arguments);
});

SamuraiJack1
2 Dec 2008, 1:48 AM
http://extjs-ux.org/docs/?class=Ext.ux.event.Broadcast

mjack003
2 Dec 2008, 7:52 AM
@Jack -- Nice Jack, thanks for the info. Will help cut down on code length and from having to hard code my message bus all over. With some simple logic I can use this to publish only certain events. I love this library. Is there a link for contributions? I really don't need a commercial license as this is all an internal project but I'm sure I could convince the company I work for to make a contribution to show support.

@Samurai -- I've looked at the extension and this is handy piece of code for a simple bus ...but not for the scope of the project I'm working on. I haven't looked at the licensing on your extension but I would need to heavily modify it as our project grows.

SamuraiJack1
2 Dec 2008, 9:15 AM
@Samurai -- I've looked at the extension and this is handy piece of code for a simple bus ...but not for the scope of the project I'm working on. I haven't looked at the licensing on your extension but I would need to heavily modify it as our project grows.

Well, lets say the license is BSD, feel free to improve it. Here's the link to svn:
http://extjs-ux.org/repo/authors/SamuraiJack/trunk/Ext/ux/event/Broadcast.js

mjack003
2 Dec 2008, 11:02 AM
Sounds good, I'll keep you updated so you can add the useful bits to the existing extension.

Mjack