You are currently viewing a snapshot of www.mozilla.org taken on April 21, 2008. Most of this content is highly out of date (some pages haven't been updated since the project began in 1998) and exists for historical purposes only. If there are any pages on this archive site that you think should be added back to www.mozilla.org, please file a bug.



Broadcasters and Observers

Feature Owner
David Hyatt

In many cases user interface elements actually represent the same object. For example, a Cut menu item represents the same command as a Cut toolbar button. The two elements should both be enabled or disabled at the same time, and the actions they perform should also be identical.

Broadcasters and observers provide a mechanism for allowing multiple elements to observe a single element that can broadcast state and event information to its observers.

Broadcasters and observers should only be used when attribute or event information must be communicated to multiple observers simultaneously. Broadcasters and observers should not be used simply to transmit information from one element to another element. The relationship should be one-to-many.

Any element in a XUL document can be a broadcaster or observer. This relationship is completely arbitrary and can exist between any two elements, although typically this relationship will exist between an invisible element (used simply for storing common state and event handlers) and multiple user interface elements (usually key bindings, menus, and toolbar buttons).

An element can become an observer of another element either programmatically or through the use of observes nodes. An observes node can be attached as a child of the node that will become the observer. The observes node can have several attributes.

The element attribute points to the node that represents the broadcaster. Its value is the id of the broadcaster. getElementById is used to retrieve the broadcaster and to attach it to the observer.

The attribute attribute indicates an attribute of the broadcaster that the observer is watching. For example, a toolbar button could observe the disabled attribute of the broadcaster. If the attribute is set or unset on the broadcaster, it will automatically be set or unset in the observer. If this attribute has a value of*, then the observer will pick up all of the broadcaster's attributes (except for id). The * functionality is not yet implemented.

<broadcaster id="cut"/>
...
<menuitem name="Cut">
  <observes element="cut" attribute="disabled"/>
</menuitem>
...
<titledbutton value="Cut">
  <observes element="cut" attribute="disabled"/>
</titledbutton>
...

There is also a simpler syntax that can be used when one node simply wishes to observe all the attributes on a broadcaster node. Instead of having to use an observes node, an observes attribute can be placed on the observer instead. Its value is the id of the broadcaster being observed. When this is done all attributes on the observer (with the exception of id) will be picked up from the broadcaster.

Not yet implemented, probably won't be The mapto attribute can be used to select a different attribute to set/unset in the observer when the attribute specified by the attribute is set/unset in the broadcaster. For example, an action attribute in the broadcaster might be mapped to an onclick attribute in a menu item and to an onkeydown attribute in a key binding.

<broadcaster id="cut" action="performCut()"/>
...
<menuitem name="Cut">
  <observes element="cut" attribute="action" mapto="onclick"/>
</menuitem>
...

Not yet implemented, probably won't be The event attribute can be used to indicate that an observer wants to observe a particular event, such as a mouse click. The value of this attribute corresponds to the event that would be specified using the addEventListener AOM API. (See Event Observation for details.) When this attribute is used, then any event handlers that are added or removed from the broadcaster will also be added or removed from the observer.

<broadcaster id="cut"/>
...
<menuitem name="Cut">
  <observes element="cut" event="click"/>
</menuitem>
...
document.getElementById('cut').addEventListener('click', performCut);
...
function performCut() {
  ...
}

The observes node can also have a change event handler placed on it, either through script or by placing an onchange attribute on the observes node. This handler is invoked whenever an attribute changes. Currently the handler is only invoked when an attribute is set, but not when it is unset. This is a known problem. The code in the handler executes in the context of the element that is the observer, i.e., the parent of the observes element.

Implemented, but the map argument hasn't been added yet. In addition to observes nodes, the broadcaster/observer relationship can be set up programmatically using the addBroadcastListener, removeBroadcastListener, addBroadcastEventListener, and removeBroadcastEventListener AOM methods.

addBroadcastListener takes a DOM element, an attribute, and a mapto. removeBroadcastListener takes a DOM element and an attribute.

The event listener versions of the methods have the same set of arguments, with the event in place of the attribute argument.

Not yet implemented. The addBroadcastChangeListener and removeBroadcastChangeListener methods can be used to programmatically add and remove change handlers. They take the same arguments as addBroadcastListener and removeBroadcastListener, except that the mapto argument is a function that will be invoked when the attribute changes instead.

All of these methods are invoked on the elements that will be the broadcasters.

<broadcaster id="cut"/>
...
<menuitem id="cutMenu" name="Cut"/>
...
<titledbutton id="cutButton" value="Cut"/>
...
var cutMenu = document.getElementById('cutMenu');
var cutButton = document.getElementById('cutButton');
document.getElementById('cut').addBroadcastListener(cutMenu, 'disabled', 'disabled');
document.getElementById('cut').addBroadcastListener(cutButton, 'disabled', 'disabled');
...

Finally it is worth noting that a broadcaster must be in the XUL namespace. An HTML element cannot function as a broadcaster. Any element, however, can be an observer.

Command Nodes

Broadcasters are typically used to represent command nodes that communicate state and/or the appropriate command execution code to multiple UI elements. The three common UI elements that observe command broadcasters are menu items, toolbar buttons, and key bindings.

For example, imagine a "save" broadcaster. That broadcaster can have an oncommand handler hooked up to it that contains the JS code that should be executed when the command is invoked. You can also place the display text of the command in the value attribute and poke the disabled attribute on the broadcaster to enable or disable the command.

<broadcaster id="saveCommand" value="Save" oncommand="PerformSave()"
  disabled="true"/>
...
<menuitem id="saveMenu" key="saveKey" observes="saveCommand"/>
...
<titledbutton id="saveButton" observes="saveCommand"/>
...
<key id="saveKey" control="true" key="s" observes="saveCommand"/>