Manipulating Lists
The XUL listbox provides a number of specialized methods.
List Manipulation
The listbox element provides numerous methods to retrieve and manipulate its items. Although listboxes may be manipulated using the standard DOM functions as well, it is recommended that the specialized listbox functions be used instead when possible. These functions are bit simpler and will do the right thing.
The appendItem function is used to append a new item to the end a list. Similar to the DOM appendChild function except that it takes a string label, and you do not have to worry about where to add it in the list structure. Here is an example:
Example 7.3.1: Source View<script> function addItem() { document.getElementById('thelist').appendItem("Thursday", "thu"); } </script> <listbox id="thelist"/> <button label="Add" oncommand="addItem();"/>
The appendItem takes two arguments, the label, in this case 'Thursday', and a value 'thu'. The two arguments correspond to the label attribute and the value attribute on the listitem element. The value is used only as an extra optional value associated with an item which you might wish to use in a script.
Similarly, there is also an insertItemAt and a removeItemAt function which inserts a new item and removes an existing item respectively. The syntax is as follows:
list.insertItemAt(3, "Thursday", "thu"); list.removeItemAt(3);
The insertItemAt function takes an additional argument, the position to insert the new item. The new item is inserted at this index, so, in the example, the new item will be added at position 3 while the item previously at that position will now be at position 4. Remember that the first item is 0. The removeItemAt function will remove the item at a specific index.
These three methods are also available for several other XUL elements and work in the same manner. In fact, these methods are part of the nsIDOMXULSelectControlElement interface so any XUL elements which implement this interface have these methods. This includes the menulist, radiogroup and tabs elements. For example, to add a new item to a menulist, you can use the same syntax as for a listbox. The right kind of element will be appended in each situation.
List Selection
The nsIDOMXULSelectControlElement interface provides two additonal properties, selectedIndex and selectedItem. The former returns the index of the selected item while the latter returns the selected element. For instance the selectedItem of a menulist will be the menuitem that is selected. If no item is selected, selectedIndex will return -1, while selectedItem will return null.
These two properties are commonly inspected during a select event, as in the following example:
Example 7.3.2: Source View<listbox id="thelist" onselect="alert(this.selectedItem.label);"> <listitem label="Short"/> <listitem label="Medium"/> <listitem label="Tall"/> </listbox>
The select event is fired for a listbox when an item in the list is selected. The select handler here displays an alert containing the label of the selected item in the list. Since the select event fired we can assume that an item is selected. In other cases, you may wish to check to ensure that selectedItem is not null before continuing.
The select event is also fired when a radio button in a radiogroup is selected and when a tab is selected in a tabs element. However, menulists do not fire the select event; instead you can listen to the command event to handle when an item is selected.
For the tabs element, it is often more convenient to use functions of the tabbox element instead. It also has a selectedIndex function which will return the index of the selected tab. However, to get the selected item, use the tabbox's selectedTab function instead. Or, use the selectedPanel function to get the selected panel, that is, return the content associated with the tab.
All of the selection related properties described above may be also be assigned a new value to change the selection. In the next example, the selectedIndex property of a radiogroup element is changed based on the value entered in a textbox. This code isn't foolproof though; for example it doesn't check if the value entered is out of range. You will want to make sure that you add this kind of error checking.
Example 7.3.3: Source View<script> function doSelect() { var val = document.getElementById('number').value; val = Number(val); if (val != null) document.getElementById('level').selectedIndex = val - 1; } </script> <hbox align="center"> <label value="Enter a number from 1 to 3:"/> <textbox id="number"/> <button label="Select" oncommand="doSelect();"/> </hbox> <radiogroup id="level"> <radio label="Excellent"/> <radio label="Good"/> <radio label="Poor"/> </radiogroup>
Listboxes also support multiple selection and the functions of the nsIDOMXULMultiSelectControlElement interface. This interface provides a number of functions specifically for handling multiple selection. For example the selectedItems property holds a list of the items that are selected, while the selectedCount property holds the number of items selected. Typically, you will use these properties to iterate over the list and perform some operation for each item. Be careful when iterating over the selected items; if you modify the items in the list while iterating, the list will change and the selection properties may return different values. This is one reason why it is useful to manipulate the list by the item rather than by index.
The following example shows a method of deleting the selected items properly:
Example 7.3.4: Source View<script> function deleteSelection() { var list = document.getElementById('thelist'); var count = list.selectedCount; while (count--){ var item = list.selectedItems[0]; list.removeItemAt(list.getIndexOfItem(item)); } } </script> <button label="Delete" oncommand="deleteSelection();"/> <listbox id="thelist" seltype="multiple"> <listitem label="Cheddar"/> <listitem label="Cheshire"/> <listitem label="Edam"/> <listitem label="Gouda"/> <listitem label="Havartie"/> </listbox>
Inside the while loop, we first get the selected item at index 0. The first selected item is always retrieved as the size of the array will decrease as the items are removed. Next, we remove the item using the removeItemAt function. Since this function requires an index, we can convert between an item and an index using the getIndexOfItem function. There is also a corresponding getItemAtIndex function to do the reverse.
The nsIDOMXULMultiSelectControlElement interface also provides methods for modifying the selected items. For instance, the addItemToSelection function adds a new item to the set of selected items, without clearing the existing selection. The removeItemFromSelection function removes a single item from the selection.
List Scrolling
If there are more rows in the listbox than can be displayed, a scroll bar will appear to allow the user to scroll the list. The scroll position may be adjusted using a couple of listbox methods.
The scrollToIndex method scrolls to a given row. This listbox will scroll such that the row will be the top row visible, unless the row is near the end of the list of items. The ensureIndexIsVisible method is similar in that it also scrolls to show a row, but this method does not scroll if the item is already visible. Thus, the former function is used to scroll to a specific row while the latter is used just to make sure that a row is visible. There is also an ensureItemIsVisible that takes an item as an argument instead of an index. Compare the effect of both functions at different scroll positions in this example:
Example 7.3.5: Source View<button label="scrollToIndex" oncommand="document.getElementById('thelist').scrollToIndex(4);"/> <button label="ensureIndexIsVisible" oncommand="document.getElementById('thelist').ensureIndexIsVisible(4);"/> <listbox id="thelist" rows="5"> <listitem label="1"/> <listitem label="2"/> <listitem label="3"/> <listitem label="4"/> <listitem label="5"/> <listitem label="6"/> <listitem label="7"/> <listitem label="8"/> <listitem label="9"/> <listitem label="10"/> <listitem label="11"/> <listitem label="12"/> </listbox>
(Next) Next, we'll look at XUL box objects.