Skip to content

Commit 0ad82c9

Browse files
committed
add close on select prop
1 parent f7f8fb4 commit 0ad82c9

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

components/dash-core-components/src/components/Dropdown.react.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ Dropdown.propTypes = {
118118
*/
119119
multi: PropTypes.bool,
120120

121+
/**
122+
* If false and multi=true, then selecting a value will leave the menu open
123+
* to select more values
124+
*/
125+
close_on_select: PropTypes.bool,
126+
121127
/**
122128
* Whether or not the dropdown is "clearable", that is, whether or
123129
* not a small "x" appears on the right of the dropdown that removes
@@ -229,6 +235,7 @@ Dropdown.defaultProps = {
229235
clearable: true,
230236
disabled: false,
231237
multi: false,
238+
close_on_select: true,
232239
searchable: true,
233240
optionHeight: 35,
234241
maxHeight: 200,

components/dash-core-components/src/fragments/Dropdown.react.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const TOKENIZER = {
2424

2525
const RDProps = [
2626
'multi',
27+
'close_on_select',
2728
'clearable',
2829
'searchable',
2930
'search_value',
@@ -41,6 +42,7 @@ const Dropdown = props => {
4142
clearable,
4243
searchable,
4344
multi,
45+
close_on_select,
4446
options,
4547
setProps,
4648
style,
@@ -53,7 +55,9 @@ const Dropdown = props => {
5355
if (!persistentOptions || !isEqual(options, persistentOptions.current)) {
5456
persistentOptions.current = options;
5557
}
56-
58+
if (!multi) {
59+
setProps({close_on_select: true});
60+
}
5761
const [sanitizedOptions, filterOptions] = useMemo(() => {
5862
let sanitized = sanitizeOptions(options);
5963

@@ -155,6 +159,7 @@ const Dropdown = props => {
155159
filterOptions={filterOptions}
156160
options={sanitizedOptions}
157161
value={value}
162+
closeOnSelect={close_on_select}
158163
onChange={onChange}
159164
onInputChange={onInputChange}
160165
backspaceRemoves={clearable}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import json
2+
3+
from dash import Dash, Input, Output, dcc, html
4+
from selenium.webdriver.common.keys import Keys
5+
6+
7+
def test_ddcos001_multi_stay_open(dash_dcc):
8+
app = Dash(__name__)
9+
app.layout = html.Div(
10+
[
11+
dcc.Dropdown(
12+
id="multi-dropdown",
13+
options=[
14+
{"label": "New York City", "value": "NYC"},
15+
{"label": "Montreal", "value": "MTL"},
16+
{"label": "San Francisco", "value": "SF"},
17+
],
18+
multi=True,
19+
close_on_select=False,
20+
),
21+
html.Div(id="dropdown-value", style={"height": "10px", "width": "10px"}),
22+
]
23+
)
24+
25+
@app.callback(
26+
Output("dropdown-value", "children"),
27+
[Input("multi-dropdown", "value")],
28+
)
29+
def update_value(val):
30+
return json.dumps([v for v in val])
31+
32+
dash_dcc.start_server(app)
33+
dropdown = dash_dcc.find_element("#multi-dropdown")
34+
dropdown.click()
35+
outer_menu = dash_dcc.find_element("#multi-dropdown .Select-menu-outer")
36+
outer_menu.click()
37+
dash_dcc.wait_for_contains_class("#multi-dropdown .Select", "is-open")
38+
outer_menu.click()
39+
dash_dcc.wait_for_contains_class("#multi-dropdown .Select", "is-open")
40+
dash_dcc.find_element("body").send_keys(Keys.ESCAPE)
41+
42+
dash_dcc.wait_for_text_to_equal("#dropdown-value", '["MTL", "SF"]')
43+
44+
45+
def test_ddcos002_multi_close(dash_dcc):
46+
app = Dash(__name__)
47+
app.layout = html.Div(
48+
[
49+
dcc.Dropdown(
50+
id="multi-dropdown",
51+
options=[
52+
{"label": "New York City", "value": "NYC"},
53+
{"label": "Montreal", "value": "MTL"},
54+
{"label": "San Francisco", "value": "SF"},
55+
],
56+
multi=True,
57+
close_on_select=True,
58+
),
59+
html.Div(id="dropdown-value", style={"height": "10px", "width": "10px"}),
60+
]
61+
)
62+
63+
@app.callback(
64+
Output("dropdown-value", "children"),
65+
[Input("multi-dropdown", "value")],
66+
)
67+
def update_value(val):
68+
return json.dumps([v for v in val])
69+
70+
dash_dcc.start_server(app)
71+
dropdown = dash_dcc.find_element("#multi-dropdown")
72+
dropdown.click()
73+
outer_menu = dash_dcc.find_element("#multi-dropdown .Select-menu-outer")
74+
outer_menu.click()
75+
dash_dcc.wait_for_no_elements("#multi-dropdown .Select-menu-outer")
76+
dash_dcc.find_element("body").send_keys(Keys.ESCAPE)
77+
78+
dash_dcc.wait_for_text_to_equal("#dropdown-value", '["MTL"]')
79+
80+
81+
def test_ddcos003_single_open(dash_dcc):
82+
app = Dash(__name__)
83+
app.layout = html.Div(
84+
[
85+
dcc.Dropdown(
86+
id="multi-dropdown",
87+
options=[
88+
{"label": "New York City", "value": "NYC"},
89+
{"label": "Montreal", "value": "MTL"},
90+
{"label": "San Francisco", "value": "SF"},
91+
],
92+
close_on_select=True,
93+
),
94+
html.Div(id="dropdown-value", style={"height": "10px", "width": "10px"}),
95+
]
96+
)
97+
98+
@app.callback(
99+
Output("dropdown-value", "children"),
100+
[Input("multi-dropdown", "value")],
101+
)
102+
def update_value(val):
103+
return json.dumps(val)
104+
105+
dash_dcc.start_server(app)
106+
dropdown = dash_dcc.find_element("#multi-dropdown")
107+
dropdown.click()
108+
outer_menu = dash_dcc.find_element("#multi-dropdown .Select-menu-outer")
109+
outer_menu.click()
110+
dash_dcc.wait_for_no_elements("#multi-dropdown .Select-menu-outer")
111+
dash_dcc.find_element("body").send_keys(Keys.ESCAPE)
112+
113+
dash_dcc.wait_for_text_to_equal("#dropdown-value", '"MTL"')

0 commit comments

Comments
 (0)