This example illustrates how to use Button to mimic the behavior of an
HTML <select>
element.
By including the Menu family of controls, it is
possible to create menu buttons that mimic the behavior of HTML
<select>
elements.
Menu buttons can either replace existing <select>
elements
or can be created completely from script.
To replace an existing <select>
element with a menu button,
simply set the Button's menu
attribute to the id of the
<select>
element using an object literal passed to the
Button's constructor. In this example, the following snippets of HTML and
JavaScript are used to transform the first <select>
element
into a menu button.
1 | <select id="select-1" name="select-1"> |
2 | <option value="select-1-1" selected>Option 1</option> |
3 | <option value="select-1-2">Option 2</option> |
4 | <option value="select-1-3">Option 3</option> |
5 | </select> |
view plain | print | ? |
1 | var oMenuButton1 = new Button({ |
2 | id: "menubutton-1", |
3 | name: "menubutton-1", |
4 | label: "<em class=\"yui-button-label\">Option 1</em>", |
5 | type: "menu", |
6 | menu: "select-1", |
7 | container: "select-1-container" |
8 | }); |
view plain | print | ? |
To create a menu button without existing markup, simply set the menu
configuration property to an array of
MenuItem configuration
properties, as illustrated by the code used to create the third menu
button in this example:
1 | var aMenuButton3MenuData = [ |
2 | { text: "Option 1", value: "menubutton-3-1" }, |
3 | { text: "Option 2", value: "menubutton-3-2" }, |
4 | { text: "Option 3", value: "menubutton-3-3" } |
5 | ]; |
6 | |
7 | var oMenuButton3 = new Button({ |
8 | id: "menubutton-3", |
9 | name: "menubutton-3", |
10 | label: "<em class=\"yui-button-label\">Option 1</em>", |
11 | type: "menu", |
12 | menu: aMenuButton3MenuData, |
13 | container: "menubutton-3-container" }); |
view plain | print | ? |
<select>
Behavior & Style Customizations
To mimic the behavior of an HTML <select>
element, the
label of the Button needs to reflect the currently selected MenuItem in the
Button's Menu. To update the Button's label
attribute when the
user clicks on a MenuItem, simply register a listener for the Button's
selectedMenuItemChange
event that sets the value of the
Button's label
attribute to the value of the text
configuration property of the selected MenuItem instance. The following
example illustrates how a selectedMenuItemChange
event listener
is added to the first Button in this example.
1 | // "selectedMenuItemChange" event handler for a Button that will set |
2 | // the Button's "label" attribute to the value of the "text" |
3 | // configuration property of the MenuItem that was clicked. |
4 | |
5 | var onSelectedMenuItemChange = function (event) { |
6 | |
7 | var oMenuItem = event.newValue; |
8 | |
9 | this.set("label", ("<em class=\"yui-button-label\">" + |
10 | oMenuItem.cfg.getProperty("text") + "</em>")); |
11 | |
12 | }; |
13 | |
14 | // Register a "selectedMenuItemChange" event handler that will sync the |
15 | // Button's "label" attribute to the MenuItem that was clicked. |
16 | |
17 | oMenuButton1.on("selectedMenuItemChange", onSelectedMenuItemChange); |
view plain | print | ? |
It is also necessary to customize the style of the menu button, to indicate
the currently selected item in each Button's menu. When the value of the
Button's selectedMenuItem
attribute changes, Button adds a class
named "yui-button-selectedmenuitem" to the <li>
element of
the currently selected MenuItem. This class can be used to provide a custom
style to the currently selected MenuItem in a Button's Menu. In this example,
a Button's currently selected MenuItem is rendered with a check mark to the
left of its text label.
In addition to styling a Button's selected MenuItem, the label of each Button
in this example is set to a fixed width. This is is accomplished by wrapping
the text label of each Button in an <em>
tag and setting
the <em>
's width
property to 5em
,
and the overflow
property to hidden
.
1 | .yui-menu-button em.yui-button-label { |
2 | |
3 | font-style: normal; |
4 | display: block; |
5 | text-align: left; |
6 | white-space: nowrap; |
7 | |
8 | /* Restrict the width of the label to 5em. */ |
9 | width: 5em; |
10 | |
11 | /* Hide the overflow if the text label exceeds 5em in width. */ |
12 | overflow: hidden; |
13 | |
14 | /* |
15 | IE, Safari and Opera support the ability to add ellipsis when the text |
16 | label exceeds 10em in width. |
17 | */ |
18 | text-overflow: ellipsis; |
19 | -o-text-overflow: ellipsis; |
20 | |
21 | } |
22 | |
23 | li.yui-button-selectedmenuitem { |
24 | background: url(../button/assets/checkbox.png) left center no-repeat; |
25 | } |
view plain | print | ? |
In HTML, it is possible to specify a default value for a
<select>
element by applying the selected
attribute to one of the <select>
's
<option>
elements. If a menu button is replacing an
existing <select>
element, the default value will
automatically be interpreted from the <select>
's
<option>
elements.
If a default value is desired for a menu button built completely from script,
it is necessary to specify the default value by setting the
selectedMenuItem
attribute. The following code illustrates how
a default value was specified for the the fourth Button in this example.
1 | var aMenuButton4MenuData = [ |
2 | { text: "Option 1", value: "menubutton-4-1" }, |
3 | { text: "Option 2", value: "menubutton-4-2" }, |
4 | { text: "Option 3", value: "menubutton-4-3" } |
5 | ]; |
6 | |
7 | var oMenuButton4 = new Button({ |
8 | id: "menubutton-4", |
9 | name: "menubutton-4", |
10 | label: "<em class=\"yui-button-label\">Option 1</em>", |
11 | type: "menu", |
12 | lazyloadmenu: false, |
13 | menu: aMenuButton4MenuData, |
14 | container: "menubutton-4-container" }); |
15 | |
16 | var oMenuButton4Menu = oMenuButton4.getMenu(); |
17 | |
18 | |
19 | // "render" event handler for a Button's Menu - responsible for setting |
20 | // the default value for the Button's "selectedMenuItem" attribute. |
21 | |
22 | var onMenuRender = function (type, args, button) { |
23 | |
24 | button.set("selectedMenuItem", this.getItem(0)); |
25 | |
26 | }; |
27 | |
28 | // If a Button's "selectedMenuItem" attribute is set, the selected |
29 | // MenuItem's name and value will be part of the form's data set |
30 | // when its parent form is submitted. For Buttons with Menus built |
31 | // entirely from script, the "selectedMenuItem" property is not set by |
32 | // default. To set the "selectedMenuItem" to a default value, simply |
33 | // register a "render" event handler for the Button's Menu that sets |
34 | // the Button's "selectedMenuItem" attribute to the desired item in |
35 | // the Menu. |
36 | |
37 | oMenuButton4Menu.subscribe("render", onMenuRender, oMenuButton4); |
view plain | print | ? |
For performance, a Button's Menu is lazy loaded by default — the MenuItems
are initialized and the Menu's HTML is rendered to the page the first time the
Button is clicked. If the user never clicks on the Button, its Menu
will never be rendered, meaning the render
event handler used to
set the default value of the selectedMenuItem
attribute will never
be called. In such cases it is necessary to add a submit
event
handler to the Button's parent form that will render the Menu if the Button's
selectedMenuItem
attribute is not set. The following code
illustrates how a submit
event handler is added to the parent
form of the third button in this example.
1 | // "render" event handler for a Button's Menu - responsible for setting |
2 | // the default value for the Button's "selectedMenuItem" attribute. |
3 | |
4 | var onMenuRender = function (type, args, button) { |
5 | |
6 | button.set("selectedMenuItem", this.getItem(0)); |
7 | |
8 | }; |
9 | |
10 | |
11 | // "selectedMenuItemChange" event handler for a Button that will set |
12 | // the Button's "label" attribute to the value of the "text" |
13 | // configuration property of the MenuItem that was clicked. |
14 | |
15 | var onSelectedMenuItemChange = function (event) { |
16 | |
17 | var oMenuItem = event.newValue; |
18 | |
19 | this.set("label", ("<em class=\"yui-button-label\">" + |
20 | oMenuItem.cfg.getProperty("text") + "</em>")); |
21 | |
22 | }; |
23 | |
24 | |
25 | // "submit" event handler for a Button's parent form - repsonsible for |
26 | // rendering a Menu that was to be lazy loaded, but never clicked on, |
27 | // and therefore never rendered. |
28 | |
29 | var onFormSubmit = function (event, button) { |
30 | |
31 | var oMenuItem = button.get("selectedMenuItem"), |
32 | UA = YAHOO.env.ua, |
33 | oEvent, |
34 | oMenu; |
35 | |
36 | if (!oMenuItem) { |
37 | |
38 | // Pause submission of the form until the Button's Menu |
39 | // is rendered |
40 | YAHOO.util.Event.preventDefault(event); |
41 | |
42 | oMenu = button.getMenu(); |
43 | |
44 | oMenu.addItems(oMenu.itemData); |
45 | |
46 | oMenu.subscribe("render", function () { |
47 | |
48 | var bSubmitForm; |
49 | |
50 | if (UA.ie) { |
51 | bSubmitForm = this.fireEvent("onsubmit"); |
52 | } |
53 | else { // Gecko, Opera, and Safari |
54 | |
55 | oEvent = document.createEvent("HTMLEvents"); |
56 | oEvent.initEvent("submit", true, true); |
57 | bSubmitForm = this.dispatchEvent(oEvent); |
58 | |
59 | } |
60 | |
61 | // In IE and Safari, dispatching a "submit" event to a form |
62 | // WILL cause the form's "submit" event to fire, but WILL |
63 | // NOT submit the form. Therefore, we need to call the |
64 | // "submit" method as well. |
65 | |
66 | if ((UA.ie || UA.webkit) && bSubmitForm) { |
67 | this.submit(); |
68 | } |
69 | |
70 | }, this, true); |
71 | |
72 | oMenu.render(oMenu.cfg.getProperty("container")); |
73 | |
74 | } |
75 | |
76 | }; |
77 | |
78 | var aMenuButton3MenuData = [ |
79 | { text: "Option 1", value: "menubutton-3-1" }, |
80 | { text: "Option 2", value: "menubutton-3-2" }, |
81 | { text: "Option 3", value: "menubutton-3-3" } |
82 | ]; |
83 | |
84 | var oMenuButton3 = new Button({ |
85 | id: "menubutton-3", |
86 | name: "menubutton-3", |
87 | label: "<em class=\"yui-button-label\">Option 1</em>", |
88 | type: "menu", |
89 | menu: aMenuButton3MenuData, |
90 | container: "menubutton-3-container" }); |
91 | |
92 | // Register a "selectedMenuItemChange" event handler that will sync the |
93 | // Button's "label" attribute to the MenuItem that was clicked. |
94 | |
95 | oMenuButton3.on("selectedMenuItemChange", onSelectedMenuItemChange); |
96 | |
97 | oMenuButton3.on("appendTo", function () { |
98 | |
99 | var oMenu = this.getMenu(); |
100 | |
101 | // If a Button's "selectedMenuItem" attribute is set, the selected |
102 | // MenuItem's name and value will be part of the form's data set |
103 | // when its parent form is submitted. For Buttons with Menus built |
104 | // entirely from script, the "selectedMenuItem" property is not |
105 | // set by default. To set the "selectedMenuItem" to a default |
106 | // value, simply register a "render" event handler for the Button's |
107 | // Menu that sets the Button's "selectedMenuItem" attribute to the |
108 | // desired item in the Menu. |
109 | |
110 | oMenu.subscribe("render", onMenuRender, this); |
111 | |
112 | |
113 | // The items in a Button's Menu are lazy loaded by default: loaded |
114 | // when the Button is initially clicked. If the user never clicks |
115 | // on the Button, its Menu will never be rendered, meaning the |
116 | // "render" event handler registered above will never be called, |
117 | // and the default value for the Button's "selectMenuItem" |
118 | // attribute will never be set. Therefore, add a "submit" event |
119 | // handler to the Button's parent form that will render the Menu |
120 | // if the Button's "selectedMenuItem" attribute is not set. |
121 | |
122 | YAHOO.util.Event.on(this.getForm(), "submit", onFormSubmit, this); |
123 | |
124 | }); |
view plain | print | ? |
You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.
Note: Logging and debugging is currently turned off for this example.
Copyright © 2011 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Copyright Policy - Job Openings