Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Observable pattern as Joose role
JavaScript HTML
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib/JooseX check if already purged
misc - added documentation
t - tested `cancel` method of listener
.gitignore initial commit
Changes v0.03 - some tweaks for documentation
components.json - removed JXND dependency
dist.ini some cleanup


JooseX.Observable - cross-plaform implementation of the Observable pattern


    // Simple events

    Class('My.Class', {
        does    : JooseX.Observable

    var instance = new My.Class()

    var handler     = function (event, param1, param2) {
        // event.source == instance
        // param1       == 'foo'
        // param2       == 'bar'

    instance.on('event', handler, scope, { single : true, delay : 100 }) 

    instance.fireEvent('event', 'foo', 'bar')

    // Hierarchical events #1

    var handler     = function (event, param1, param2) {
        // event.source == instance
        // event.splat  == 'event'

        // param1       == 'foo'
        // param2       == 'bar'

    instance.on('/some/*', handler, scope, { single : true, buffer : 100 }) 

    instance.emit('/some/event', 'foo', 'bar')

    // Hierarchical events #2

    var handler     = function (event, param1, param2) {
        // event.source == instance
        // event.splat  == [ 'long', 'event' ]

        // param1       == 'foo'
        // param2       == 'bar'

    instance.on('/some/**', handler, scope, { single : true, buffer : 100 }) 

    instance.fireEvent('/some/long/event', 'foo', 'bar')

    // Bubbling

    Class('Container', {
        does    : JooseX.Observable

    Class('Component', {
        does    : JooseX.Observable,

        has     : {
            parentContainer : { required : true }

        methods : {

            getBubbleTarget : function () {
                return this.parentContainer

    var container   = new Container()

    var component   = new Component({
        parentContainer : container

    var handler     = function (event, param1, param2) {
        // event.source     == component
        // event.current    == container

        event.stopPropagation() // stop further bubbling

    container.on('/some/**', handler, scope, { single : true, buffer : 100 }) 

    component.fireEvent('/some/long/event', 'foo', 'bar')


From npm:

> [sudo] npm install joosex-observable         

Tarballs are available for downloading at:


In NodeJS:


In browsers (assuming you've completed the 3.1 item from this document):

<script type="text/javascript" src="/jsan/Task/Joose/Core.js"></script>
<script type="text/javascript" src="/jsan/Task/JooseX/Observable/Core.js"></script>


JooseX.Observable is a Joose role, implementing the Observable pattern. To use it, just add it to your class declaration:

    Class('My.Class', {
        does    : JooseX.Observable

In Observable pattern, class instances may notify the world about the changes in its state with "events". One can say instance "fire" or "emit" the events. Other instances may "observe" such notifications ("listen to events").

To fire (emit) the event use fireEvent or emit methods (both are identical):

    var instance = new My.Class()

    instance.fireEvent('event', 'foo', 'bar')

The first argument to this method is the event name, all other arguments becomes the arguments of the event and will be available in the listeners.

To listen the event, use the method on:

    var handler     = function (event, param1, param2) {
        // event.source == instance
        // param1       == 'foo'
        // param2       == 'bar'

    var listener = instance.on('event', handler, scope, { single : true, delay : 100 }) 

This method accept the event name, handler function, optional scope and optional options (see below for details). It returns the "listener" instance.

Each time the event being fired, all listeners with matching name will be activated. Their handler functions will always receive the instance of event as the 1st argument (see above) and then other arguments from fireEvent. The object, which fired the event is available as the source property of the event.

To remove the listener you can either pass it to the method un:


or call its remove method:


or still use the un specifying the same handler and scope as during on:

    instance.un('event', handler, scope)


If the event name will contain slash(es) /, then it will be considered hierarchical. Hierarchical events behaves pretty much the same as usual events, with couple of additional features.

The very last segment of the event name will be treated as the "event name". Other segments will be treated as the "event channel". For example:

// fires the event "foo" in the channel "/"

// fires the event "bar" in the channel "/foo"

// fires the event "" (empty string) in the channel "/foo/bar"

The same rules applies for the listeners, plus you can use the * and ** wildcards:

// will be activated by "/foo" only

// will be activated by "/foo/bar" only

// will be activated by "/foo/bar", "/foo/baz", "/foo/" (empty string)
// but not by "/foo/bar/baz" or "/bar"

// will be activated by "/foo/bar", "/foo/baz", "/foo/" (empty string), "/foo/bar/baz", "/foo/bar/baz/quix" etc
// but not by "/bar"

Hierarchical events are useful, when instance may emit a lot of different events, which can be categorized in groups, and listeners need the ability to listen on the whole group of events.

See also JooseX.Observable.Event documentation to know how to introspect the event instance.


Additionally, all events bubbles (a-la DOM). This is useful, when the instance participate in the nested "part/whole" relationships and the "whole" needs to listen the events from the inner "parts".

To use this feature, provide the implementation of the getBubbleTarget method in the consuming class:

    Class('Component', {
        does    : JooseX.Observable,

        methods : {

            getBubbleTarget : function () {

In the handler, you may call the stopPropagation method of the event, to stop bubbling:

    var handler     = function (event, param1, param2) {
        // event.source     == component
        // event.current    == container

        event.stopPropagation() // stop further bubbling

See also JooseX.Observable.Event documentation.



Number suspendCounter

Initially set to 0. When this attribute is bigger than 0 the instance won't emit any events.



on(eventName, func, scope?, options?)

This method creates a new listener for the event eventName. Listener will activate the function func using either provided scope or the event source as the scope. Optional options parameter should contain object with properties, corresponding to attributes of JooseX.Observable.Listener

Returns an instance of JooseX.Observable.Listener


un(eventName, func, scope)


This method will remove the listener from this instance. Either accept an instance of JooseX.Observable.Listener or the same arguments as were used for on



emit(eventName, param1, param2, ...)

fireEvent(eventName, param1, param2, ...)

These methods are identical and both "fires" the event (activates all listeners with names matching to eventName). The handlers of the listeners will receive the instance of JooseX.Observable.Event as the 1st argument and the remaining parameters as other arguments



Returns boolean value, indicating whether this instance has listeners for the eventName. eventName may contain * and ** wildcards.



Removes all listeners



This method increase the [suspendCounter] attribute and prevents any events from being emitted



This method decrease the [suspendCounter] attribute. As soon as it becomes 0 again, instance can emit events.


This extension is supported via github issues tracker:

For general Joose questions you can also visit #joose on or mailing list at:




Web page of this module:

General documentation for Joose:


All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at


Nickolay Platonov


This software is Copyright (c) 2010 by Nickolay Platonov.

This is free software, licensed under:

The GNU Lesser General Public License, Version 3, June 2007

Something went wrong with that request. Please try again.