Broadcasters and Observers

[Table of Contents] [Previous: The Box System] [Next: Focus and Command Dispatching]

Feature Owners: David Hyatt, Chris Saari

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>
...

[Not yet implemented] 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] 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.


[Table of Contents] [Previous: The Box System] [Next: Focus and Command Dispatching]
Contact us at xptoolkitstaff@netscape.com. Want to complain about the new documentation? Email Dave Hyatt.