The first approach was Simple Message Bus Example but that is more concept proof than a really usable way in production environment.
I like the concept of message subjects (topics) as dot separated sequence of tokens with the ability to subscribe to messages with specific subjects and with wildcard support.
For example, if a component would subscribe to the subject eu.extjs.desktop.**
it would receive message with subject eu.extjs.desktop.wallpaper.set
but it wouldn’t receive message eu.extjs.taskbar.hide
.
So this plugin was born.
Ext.ux.MsgBus fits in any component that is descendant of Ext.util.Observable and it does not need any other changes/overrides. You would stick it only into the components that must participate in bus messaging. It adds subscribe
and publish
methods to the component.
Usage example:
var p = new Ext.Panel({ plugins:['msgbus'] ,onWallpaper:function(subject, message) { // do something } // the rest of config }); p.subscribe('eu.extjs.desktop.wallpaper.**', {fn:p.onWallpaper, single:true});
The above would call p.onWallpaper callback once upon the receipt of a “wallpaper” message.
Other example:
p.publish('eu.extjs.this.panel.move', {oldx:100, oldy:200, x:300, y:400});
I haven’t tested it fully yet so take it more as an initial idea than as a bullet-proof, worldwide-tested code. Also, I didn’t try in any means to implement OpenAjax standards and use this plugin for an inter library communication. Consider it as a one possibility of intra-Ext, inter-component communication.
Any comments and/or bug reports are welcome.
// vim: sw=4:ts=4:nu:nospell:fdc=4 /** * Message Bus Plugin * * @author Ing. Jozef Sakáloš * @copyright (c) 2009, by Ing. Jozef Sakáloš * @date 19. September 2009 * @version $Id: Ext.ux.MsgBus.js 29 2009-09-23 09:51:55Z jozo $ * * @license Ext.ux.MsgBus.js is licensed under the terms of the Open Source * LGPL 3.0 license. Commercial use is permitted to the extent that the * code/component(s) do NOT become part of another Open Source or Commercially * licensed development library or toolkit without explicit permission. * * License details: http://www.gnu.org/licenses/lgpl.html */ /*global Ext,window */ /** * @class Ext.ux.MsgBus * * Creates new Ext.ux.MsgBus object * @constructor * @param {Object} config The config object */ Ext.ux.MsgBus = function(config) { Ext.apply(this, config, { }); }; // eo constructor Ext.override(Ext.ux.MsgBus, { /** * @cfg {String} busName Name of the global Observable instance */ busName:'Ext.ux.Bus' /** * @private */ ,bus:false /** * Initializes the plugin and component * @private */ ,init:function(cmp) { this.cmp = cmp; cmp.bus = this.getBus(); cmp.bus.addEvents('message'); cmp.subs = {}; this.applyConfig(); } // eo function init // {{{ /** * Returns or creates the global Observable instance * @private */ ,getBus:function() { var bus = window; var a = this.busName.split('.'); var last = a.pop(); Ext.each(a, function(n) { if(!Ext.isObject(bus[n])) { bus = false; return false; } else { bus = bus[n]; } }, this); if(false === bus) { Ext.ns(this.busName); return this.getBus(); } if(!(bus[last] instanceof Ext.util.Observable)) { bus[last] = new Ext.util.Observable(); } return bus[last]; } // eo function getBus // }}} // {{{ /** * Creates RegExp for message filtering. * Override it if you need another logic. * @param {String} subject The message subject * @return {RegExp} RegExp used for message filtering */ ,getFilterRe:function(subject) { var a = subject.split('.'); var last = a.length - 1; a[last] = '**' === a[last] ? '.*' : a[last]; var re = /^w+$/; Ext.each(a, function(token, i) { if(!re.test(token) && '*' !== token && '.*' !== token) { throw 'Invalid subject: ' + subject; } if('*' === token) { a[i] = '\w+'; } }); return new RegExp('^' + a.join('\.') + '$'); } // eo function getFilter // }}} // {{{ /** * Applies new methods to the component * @private */ ,applyConfig:function() { Ext.applyIf(this.cmp, { /** * Subscribes to messages (parent component method) * @param {String} subject Dotted notation subject with wildcards. * See http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Topic_Names * @param {Object} config Same as addListener config object * @return {Boolean} success true on success, false on failure (subscription exists) */ subscribe:function(subject, config) { var sub = this.subs[subject]; if(sub) { return false; } config = config || {}; config.filter = this.getFilterRe(subject); this.subs[subject] = {config:config, fn:this.filterMessage.createDelegate(this, [config], true)}; this.bus.on('message', this.subs[subject].fn, config.scope || this, config); return true; } /** * Unsubscribes from messages (parent component method) * @param {String} subject Dotted notation subject with wildcards. * @return {Boolean} success true on success, false on failure (nonexistent subscription) */ ,unsubscribe:function(subject) { var sub = this.subs[subject]; if(!sub) { return false; } this.bus.un('message', sub.fn, sub.scope || this, sub.config); delete this.subs[subject]; sub = null; return true; } // eo function unsubscribe /** * Publishes the message (parent component method) * @param {String} subject Message subject * @param {Mixed} message Message body, most likely an object */ ,publish:function(subject, message) { this.getFilterRe(subject); this.bus.fireEvent('message', subject, message); } // eo function publish /** * Returns current subscriptions * @return {Object} subscriptions */ ,getSubscriptions:function() { return this.subs; } // eo function /** * @private */ ,getFilterRe:this.getFilterRe /** * Filters incoming messages * @private */ ,filterMessage:function(subject, message, config) { if(config.filter.test(subject)) { (config.fn || this.onMessage).call(config.scope || this, subject, message); } } // eo function filterMessage /** * Default message processing function * @param {String} subject The message subject * @param {Mixed} message The message body */ ,onMessage:Ext.emptyFn }); } // eo function applyConfig // }}} }); // eo override // register ptype Ext.preg('msgbus', Ext.ux.MsgBus); // eof
Enjoy!
The accompanying example: Ext.ux.MsgBus
- Ext, Angular, React, and Vue - 27. June 2019
- The Site Resurgence - 11. February 2018
- Configuring ViewModel Hierarchy - 19. June 2015
28 Responses
Hello,
I cannot get http://examples.learnfromsaki.com/?ex=msgbus example.
Is it available yet?
Jean-Marc
Yeah it doesn’t work for some reason. I’m now away but I’ll take a look in a week or so.
Saki, it would be nice to see a syntax highlighter in your blog to be able to read easily code!
It shortly stopped to work after port. Syntax highlighter should be now up and running.
Hello, Saki!
First of all, thanks so much for all of your superb work – you seem to be everywhere (ExtJs is) ! 🙂
Secondly, I wanted to ask you a question about the MsgBus. It probably is a broader question about the JavaScript scope and area of visibility.
If I have 2 segments of JavaScript code within my HTML page code (that is 2 … chunks, separated by other HTML), each of the chunks rendering some UI, is it possible to use a MsgBus instance to communicate between the 2 interfaces?
Thanks.
If multiple component are in the same page then it is working fine ..but if in the object oriented manner how can i use publish/subscribe methods and most importantly where i use these methods in the component –
for Ex- component 1(Ext.panel) having button and on button click i want to open a component 2 (Ext.panel) then how & where i need to put publish and subscribe by using message bus plugins …… please give me suggestion because of this i am not able to use correctly the message bus functionality .
Can you write the example by using msgbus plugin in Object Oriented manner ?
Why because if components are there in a single page it is nicely working.. But i want in object oriented manner i dont’t know how to do it in OOP style ?
I am little confused about how the actual filtering is performed. Because the subscription is always done for ‘message’ and the publish always fires the ‘message’ event. Is the filtering used in the publish method?
I am trying to get this to work on ExtJs4..it works allright..but Its basically working by creating a listener for message and firing an event on it. No subject filtering as expected. What am I doing wrong?
Very nice idea. I’m gonna use this for my current project as to reduce the coupling.
Take a look at forum and/or learn section of http://sencha.com/learn Hint: override constructor.
Very useful stuff indeed. My approach of what I started today before i found your blog post was an event broker component that would pool all events that are relayed to it. Although I do prefer your solution of a message bus.
However, my approach was hooking the necessary code right into Ext.util.Observable, so that all objects that are descendants of Observable could communicate (right now anything thats not of the Component class won’t accept plugins). However, I failed to override Ext.util.Observable properly, my skillz are not at leet 😉
I’d love to any pointers by anyone on how to override Ext.util.Observable properly, since it seems to be quite different to overriding Component, to fit the code into the override and have the messagebus be accessible by any descendant of Observable.
re: Konstantin
I think that is a limitation of Ext, since direct Observable descendents to not take the “plugin” property. tried it on a RowSelectionModel instance and it failed as well.