Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 550403 of Broadcasters and Observers

  • Revision slug: Mozilla/Tech/XUL/Tutorial/Broadcasters_and_Observers
  • Revision title: Broadcasters and Observers
  • Revision id: 550403
  • Created:
  • Creator: Sheppy
  • Is current revision? Yes
  • Comment Fix previous/next links; 6 words added, 101 words removedXUL/Tutorial/Broadcasters_and_Observers Mozilla/Tech/XUL/Tutorial/Broadcasters_and_Observers

Revision Content

{{ PreviousNext("XUL Tutorial/Updating Commands", "XUL Tutorial/Document Object Model") }}

There may be times when you want several elements to respond to events or changes of state easily. To do this, we can use broadcasters.

Command Attribute Forwarding

We've already seen that elements such as buttons can be hooked up to commands. In addition, if you place the {{ XULAttr("disabled") }} attribute on the {{ XULElem("command") }} element, any elements hooked up to it will also become disabled automatically. This is a useful way to simplify the amount of code you need to write. The technique also works for other attributes as well. For instance, if you place a {{ XULAttr("label") }} attribute on a {{ XULElem("command") }} element, any buttons attached to the command will share the same label.

{{ Block-title("Example 1") }} : {{ Xultu-sv("ex_broadob_1.xul") }}

<command id="my_command" label="Open"/>

<button command="my_command"/>
<checkbox label="Open in a new window" command="my_command"/>

In this example, the button does not have a {{ XULAttr("label") }} attribute, however it is attached to a command that does. The button will share the label with the command. The checkbox already has a label, however, it will be overridden by the command's label. The result is that both the button and the checkbox will have the same label 'Open'.

If you were to modify the command's {{ XULAttr("label") }} attribute, the label on the button and checkbox will adjust accordingly. We saw something like this in a previous section where the {{ XULAttr("disabled") }} attribute was adjusted once and propagated to other elements.

This attribute forwarding is quite useful for a number of purposes. For instance, let's say that we want the Back action in a browser to be disabled. We would need to disable the Back command on the menu, the Back button on the toolbar, the keyboard shortcut (Alt+Left for example) and any Back commands on popup menus. Although we could write a script to do this, it is quite tedious. It also has the disadvantage that we would need to know all of the places where a Back action could be. If someone added a new Back button using an extension, it wouldn't be handled. It is convenient to simply disable the Back action and have all the elements that issue the Back action disable themselves. We can use the attribute forwarding of commands to accomplish this.

Broadcasters

There is a similar element called a {{ XULElem("broadcaster") }}. Broadcasters support attribute forwarding in the same way that commands do. They work the same as commands except that a command is used for actions, while a broadcaster is instead used for holding state information. For example, a {{ XULElem("command") }} would be used for an action such as Back, Cut or Delete. A {{ XULElem("broadcaster") }} would be used to hold, for instance, a flag to indicate whether the user was online or not. In the former case, menu items and toolbar buttons would need to be disabled when there was no page to go back to, or no text to cut or delete. In the latter case, various user interface elements might need to update when the user switches from offline mode to online mode.

The simplest broadcaster is shown below. You should always use an {{ XULAttr("id") }} attribute so that it can be referred to by other elements.

<broadcasterset>
  <broadcaster id="isOffline" label="Offline"/>
</broadcasterset>

Any elements that are watching the broadcaster will be modified automatically whenever the broadcaster has its {{ XULAttr("label") }} attribute changed. This results in these elements having a new label. Like other non-displayed elements, the {{ XULElem("broadcasterset") }} element serves as a placeholder for broadcasters. You should declare all your broadcasters inside a {{ XULElem("broadcasterset") }} element so that they are all kept together.

Making elements observers

Elements that are watching the broadcaster are called observers because they observe the state of the broadcaster. To make an element an observer, add an {{ XULAttr("observes") }} attribute to it. This is analogous to using the {{ XULAttr("command") }} attribute when attaching an element to a {{ XULElem("command") }} element. For example, to make a button an observer of the broadcaster above:

<button id="offline_button" observes="isOffline"/>

The {{ XULAttr("observes") }} attribute has been placed on the button and its value has been set to the value of the {{ XULAttr("id") }} on the broadcaster to observe. Here the button will observe the broadcaster which has the id isOffline, which is the one defined earlier. If the value of the {{ XULAttr("label") }} attribute on the broadcaster changes, the observers will update the values of their {{ XULAttr("label") }} attributes also.

We could continue with additional elements. As many elements as you want can observe a single broadcaster. You can also have only one if you wanted to but that would accomplish very little since the main reason for using broadcasters is to have attributes forwarded to multiple places. You should only use broadcasters when you need multiple elements that observe an attribute. Below, some additional observers are defined:

<broadcaster id="offline_command" label="Offline" accesskey="f"/>

<keyset>
  <key id="goonline_key" observes="offline_command" modifiers="accel" key="O"/>
</keyset>
<menuitem id="offline_menuitem" observes="offline_command"/>
<toolbarbutton id="offline_toolbarbutton" observes="offline_command"/>

In this example, both the {{ XULAttr("label") }} and the {{ XULAttr("accesskey") }} will be forwarded from the broadcaster to the key, menu item and the toolbar button. The key won't use any of the received attributes for anything, but it will be disabled when the broadcaster is disabled.

You can use a broadcaster to observe any attribute that you wish. The observers will grab all the values of any attributes from the broadcasters whenever they change. Whenever the value of any of the attributes on the broadcaster changes, the observers are all notified and they update their own attributes to match. Attributes of the observers that the broadcaster doesn't have itself are not modified. The only attributes that are not updated are the {{ XULAttr("id") }} and {{ XULAttr("persist") }} attributes; these attributes are never shared. You can also use your own custom attributes if you wish.

Broadcasters aren't used frequently as commands can generally handle most uses. One thing to point out is that there really is no difference between the {{ XULElem("command") }} element and the {{ XULElem("broadcaster") }} element. They both do the same thing. The difference is more semantic. Use commands for actions and use broadcasters for state. In fact, any element can act as broadcaster, as long as you observe it using the {{ XULAttr("observes") }} attribute.

The Observes Element

There is also a way to be more specific about which attribute of the broadcaster to observe. This involves an {{ XULElem("observes") }} element. Like its attribute counterpart, it allows you to define an element to be an observer. The {{ XULElem("observes") }} element should be placed as a child of the element that is to be the observer. An example is shown below:

{{ Block-title("Example 2") }} : {{ Xultu-sv("ex_broadob_2.xul") }}

<broadcasterset>
  <broadcaster id="isOffline" label="Offline" accesskey="f"/>
</broadcasterset>

<button id="offline_button">
  <observes element="isOffline" attribute="label"/>
</button>

Two attributes have been added to the {{ XULElem("observes") }} element. The first, {{ XULAttr("element") }}, specifies the id of the broadcaster to observe. The second, {{ XULAttr("attribute") }}, specifies the attribute to observe. The result here is that the button will receive its label from the broadcaster, and when the label is changed, the label on the button is changed. The {{ XULElem("observes") }} element itself does not change but the element it is inside changes, which in this case is a {{ XULElem("button") }}. Notice that the {{ XULAttr("accesskey") }} is not forwarded to the button, since it is not being obseved. If you wanted it to be, another {{ XULElem("observes") }} element would need to be added. If you don't use any {{ XULElem("observes") }} elements, and instead use the {{ XULAttr("observes") }} attribute directly on the button, all attributes will be observed.

Broadcast event

There is an additional event handler that we can place on the {{ XULElem("observes") }} element which is onbroadcast. The event is called whenever the observer notices a change to the attributes of the broadcaster that it is watching. An example is shown below.

{{ Block-title("Example 3") }} : {{ Xultu-sv("ex_broadob_3.xul") }}

<broadcasterset>
  <broadcaster id="colorChanger" style="color: black"/>
</broadcasterset>

<button label="Test">
  <observes element="colorChanger" attribute="style" onbroadcast="alert('Color changed');"/>
</button>

<button label="Observer"
  oncommand="document.getElementById('colorChanger').setAttribute('style','color: red');"
/>

Two buttons have been created, one labeled Test and the other labeled Observer. If you click on the Test button, nothing special happens. However, if you click on the Observer button, two things happen. First, the button changes to have red text and, second, an alert box appears with the message 'Color changed'.

What happens is the {{ XULAttr("oncommand") }} handler on the second button is called when the user presses on it. The script here gets a reference to the broadcaster and changes the style of it to have a color that is red. The broadcaster is not affected by the style change because it doesn't display on the screen. However, the first button has an observer which notices the change in style. The {{ XULAttr("element") }} and the {{ XULAttr("attribute") }} on the {{ XULElem("observes") }} tag detect the style change. The style is applied to the first button automatically.

Next, because the broadcast occured, the event handler onbroadcast is called. This results in an alert message appearing. Note that the broadcast only occurs if the attributes on the {{ XULElem("broadcaster") }} element are changed. Changing the style of the buttons directly will not cause the broadcast to occur so the alert box will not appear.

If you tried duplicating the code for the first {{ XULElem("button") }} several times, you would end up with a series of alert boxes appearing, one for each button. This is because each button is an observer and will be notified when the style changes.

Next, we'll look at using the Document Object Model with XUL elements.

{{ PreviousNext("XUL Tutorial/Updating Commands", "XUL Tutorial/Document Object Model") }}

{{ languages( { "fr": "fr/Tutoriel_XUL/Broadcasters_et_Observateurs", "ja": "ja/XUL_Tutorial/Broadcasters_and_Observers", "pl": "pl/Kurs_XUL/Rozg\u0142aszacze_oraz_obserwatory", "es": "es/Tutorial_de_XUL/Emisores_y_receptores" } ) }}

Revision Source

<p>{{ PreviousNext("XUL Tutorial/Updating Commands", "XUL Tutorial/Document Object Model") }}</p>
<p>There may be times when you want several elements to respond to events or changes of state easily. To do this, we can use broadcasters.</p>
<h3 id="Command_Attribute_Forwarding" name="Command_Attribute_Forwarding">Command Attribute Forwarding</h3>
<p>We've already seen that elements such as buttons can be hooked up to commands. In addition, if you place the <code>{{ XULAttr("disabled") }}</code> attribute on the <code>{{ XULElem("command") }}</code> element, any elements hooked up to it will also become disabled automatically. This is a useful way to simplify the amount of code you need to write. The technique also works for other attributes as well. For instance, if you place a <code>{{ XULAttr("label") }}</code> attribute on a <code>{{ XULElem("command") }}</code> element, any buttons attached to the command will share the same label.</p>
<p>{{ Block-title("Example 1") }} : {{ Xultu-sv("ex_broadob_1.xul") }}</p>
<pre>&lt;command id="my_command" label="Open"/&gt;

&lt;button command="my_command"/&gt;
&lt;checkbox label="Open in a new window" command="my_command"/&gt;
</pre>
<p>In this example, the button does not have a <code>{{ XULAttr("label") }}</code> attribute, however it is attached to a command that does. The button will share the label with the command. The checkbox already has a label, however, it will be overridden by the command's label. The result is that both the button and the checkbox will have the same label 'Open'.</p>
<p>If you were to modify the command's <code>{{ XULAttr("label") }}</code> attribute, the label on the button and checkbox will adjust accordingly. We saw something like this in a previous section where the <code>{{ XULAttr("disabled") }}</code> attribute was adjusted once and propagated to other elements.</p>
<p>This attribute forwarding is quite useful for a number of purposes. For instance, let's say that we want the Back action in a browser to be disabled. We would need to disable the Back command on the menu, the Back button on the toolbar, the keyboard shortcut (Alt+Left for example) and any Back commands on popup menus. Although we could write a script to do this, it is quite tedious. It also has the disadvantage that we would need to know all of the places where a Back action could be. If someone added a new Back button using an extension, it wouldn't be handled. It is convenient to simply disable the Back action and have all the elements that issue the Back action disable themselves. We can use the attribute forwarding of commands to accomplish this.</p>
<h3 id="Broadcasters" name="Broadcasters">Broadcasters</h3>
<p>There is a similar element called a <code>{{ XULElem("broadcaster") }}</code>. Broadcasters support attribute forwarding in the same way that commands do. They work the same as commands except that a command is used for actions, while a broadcaster is instead used for holding state information. For example, a <code>{{ XULElem("command") }}</code> would be used for an action such as Back, Cut or Delete. A <code>{{ XULElem("broadcaster") }}</code> would be used to hold, for instance, a flag to indicate whether the user was online or not. In the former case, menu items and toolbar buttons would need to be disabled when there was no page to go back to, or no text to cut or delete. In the latter case, various user interface elements might need to update when the user switches from offline mode to online mode.</p>
<p>The simplest broadcaster is shown below. You should always use an <code>{{ XULAttr("id") }}</code> attribute so that it can be referred to by other elements.</p>
<pre>&lt;broadcasterset&gt;
  &lt;broadcaster id="isOffline" label="Offline"/&gt;
&lt;/broadcasterset&gt;
</pre>
<p>Any elements that are watching the broadcaster will be modified automatically whenever the broadcaster has its <code>{{ XULAttr("label") }}</code> attribute changed. This results in these elements having a new label. Like other non-displayed elements, the <code>{{ XULElem("broadcasterset") }}</code> element serves as a placeholder for broadcasters. You should declare all your broadcasters inside a <code>{{ XULElem("broadcasterset") }}</code> element so that they are all kept together.</p>
<h3 id="Making_elements_observers" name="Making_elements_observers">Making elements observers</h3>
<p>Elements that are watching the broadcaster are called observers because they observe the state of the broadcaster. To make an element an observer, add an <code>{{ XULAttr("observes") }}</code> attribute to it. This is analogous to using the <code>{{ XULAttr("command") }}</code> attribute when attaching an element to a <code>{{ XULElem("command") }}</code> element. For example, to make a button an observer of the broadcaster above:</p>
<pre>&lt;button id="offline_button" observes="isOffline"/&gt;
</pre>
<p>The <code>{{ XULAttr("observes") }}</code> attribute has been placed on the button and its value has been set to the value of the <code>{{ XULAttr("id") }}</code> on the broadcaster to observe. Here the button will observe the broadcaster which has the id <code>isOffline</code>, which is the one defined earlier. If the value of the <code>{{ XULAttr("label") }}</code> attribute on the broadcaster changes, the observers will update the values of their <code>{{ XULAttr("label") }}</code> attributes also.</p>
<p>We could continue with additional elements. As many elements as you want can observe a single broadcaster. You can also have only one if you wanted to but that would accomplish very little since the main reason for using broadcasters is to have attributes forwarded to multiple places. You should only use broadcasters when you need multiple elements that observe an attribute. Below, some additional observers are defined:</p>
<pre>&lt;broadcaster id="offline_command" label="Offline" accesskey="f"/&gt;

&lt;keyset&gt;
  &lt;key id="goonline_key" observes="offline_command" modifiers="accel" key="O"/&gt;
&lt;/keyset&gt;
&lt;menuitem id="offline_menuitem" observes="offline_command"/&gt;
&lt;toolbarbutton id="offline_toolbarbutton" observes="offline_command"/&gt;
</pre>
<p>In this example, both the <code>{{ XULAttr("label") }}</code> and the <code>{{ XULAttr("accesskey") }}</code> will be forwarded from the broadcaster to the key, menu item and the toolbar button. The key won't use any of the received attributes for anything, but it will be disabled when the broadcaster is disabled.</p>
<p>You can use a broadcaster to observe any attribute that you wish. The observers will grab all the values of any attributes from the broadcasters whenever they change. Whenever the value of any of the attributes on the broadcaster changes, the observers are all notified and they update their own attributes to match. Attributes of the observers that the broadcaster doesn't have itself are not modified. The only attributes that are not updated are the <code>{{ XULAttr("id") }}</code> and <code>{{ XULAttr("persist") }}</code> attributes; these attributes are never shared. You can also use your own custom attributes if you wish.</p>
<p>Broadcasters aren't used frequently as commands can generally handle most uses. One thing to point out is that there really is no difference between the <code>{{ XULElem("command") }}</code> element and the <code>{{ XULElem("broadcaster") }}</code> element. They both do the same thing. The difference is more semantic. Use commands for actions and use broadcasters for state. In fact, any element can act as broadcaster, as long as you observe it using the <code>{{ XULAttr("observes") }}</code> attribute.</p>
<h3 id="The_Observes_Element" name="The_Observes_Element">The Observes Element</h3>
<p>There is also a way to be more specific about which attribute of the broadcaster to observe. This involves an <code>{{ XULElem("observes") }}</code> element. Like its attribute counterpart, it allows you to define an element to be an observer. The <code>{{ XULElem("observes") }}</code> element should be placed as a child of the element that is to be the observer. An example is shown below:</p>
<p>{{ Block-title("Example 2") }} : {{ Xultu-sv("ex_broadob_2.xul") }}</p>
<pre>&lt;broadcasterset&gt;
  &lt;broadcaster id="isOffline" label="Offline" accesskey="f"/&gt;
&lt;/broadcasterset&gt;

&lt;button id="offline_button"&gt;
  &lt;observes element="isOffline" attribute="label"/&gt;
&lt;/button&gt;
</pre>
<p>Two attributes have been added to the <code>{{ XULElem("observes") }}</code> element. The first, <code>{{ XULAttr("element") }}</code>, specifies the id of the broadcaster to observe. The second, <code>{{ XULAttr("attribute") }}</code>, specifies the attribute to observe. The result here is that the button will receive its label from the broadcaster, and when the label is changed, the label on the button is changed. The <code>{{ XULElem("observes") }}</code> element itself does not change but the element it is inside changes, which in this case is a <code>{{ XULElem("button") }}</code>. Notice that the <code>{{ XULAttr("accesskey") }}</code> is not forwarded to the button, since it is not being obseved. If you wanted it to be, another <code>{{ XULElem("observes") }}</code> element would need to be added. If you don't use any <code>{{ XULElem("observes") }}</code> elements, and instead use the <code>{{ XULAttr("observes") }}</code> attribute directly on the button, all attributes will be observed.</p>
<h4 id="Broadcast_event" name="Broadcast_event">Broadcast event</h4>
<p>There is an additional event handler that we can place on the <code>{{ XULElem("observes") }}</code> element which is <code>onbroadcast</code>. The event is called whenever the observer notices a change to the attributes of the broadcaster that it is watching. An example is shown below.</p>
<p>{{ Block-title("Example 3") }} : {{ Xultu-sv("ex_broadob_3.xul") }}</p>
<pre>&lt;broadcasterset&gt;
  &lt;broadcaster id="colorChanger" style="color: black"/&gt;
&lt;/broadcasterset&gt;

&lt;button label="Test"&gt;
  &lt;observes element="colorChanger" attribute="style" onbroadcast="alert('Color changed');"/&gt;
&lt;/button&gt;

&lt;button label="Observer"
  oncommand="document.getElementById('colorChanger').setAttribute('style','color: red');"
/&gt;
</pre>
<p>Two buttons have been created, one labeled Test and the other labeled Observer. If you click on the Test button, nothing special happens. However, if you click on the Observer button, two things happen. First, the button changes to have red text and, second, an alert box appears with the message 'Color changed'.</p>
<p>What happens is the <code>{{ XULAttr("oncommand") }}</code> handler on the second button is called when the user presses on it. The script here gets a reference to the broadcaster and changes the style of it to have a <code>color</code> that is red. The broadcaster is not affected by the style change because it doesn't display on the screen. However, the first button has an observer which notices the change in style. The <code>{{ XULAttr("element") }}</code> and the <code>{{ XULAttr("attribute") }}</code> on the <code>{{ XULElem("observes") }}</code> tag detect the style change. The style is applied to the first button automatically.</p>
<p>Next, because the broadcast occured, the event handler <code>onbroadcast</code> is called. This results in an alert message appearing. Note that the broadcast only occurs if the attributes on the <code>{{ XULElem("broadcaster") }}</code> element are changed. Changing the style of the buttons directly will not cause the broadcast to occur so the alert box will not appear.</p>
<p>If you tried duplicating the code for the first <code>{{ XULElem("button") }}</code> several times, you would end up with a series of alert boxes appearing, one for each button. This is because each button is an observer and will be notified when the style changes.</p>
<p>Next, we'll look at using the Document Object Model with XUL elements.</p>
<p>{{ PreviousNext("XUL Tutorial/Updating Commands", "XUL Tutorial/Document Object Model") }}</p>
<p>{{ languages( { "fr": "fr/Tutoriel_XUL/Broadcasters_et_Observateurs", "ja": "ja/XUL_Tutorial/Broadcasters_and_Observers", "pl": "pl/Kurs_XUL/Rozg\u0142aszacze_oraz_obserwatory", "es": "es/Tutorial_de_XUL/Emisores_y_receptores" } ) }}</p>
Revert to this revision