Skip to content

Commit 15e97b8

Browse files
authored
Merge pull request #2816 from TillerBurr/dcc-dropdown-remove-items
Fix Dropdown Option Removal Regression
2 parents 2ea44a5 + e281eb8 commit 15e97b8

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ const Dropdown = props => {
3939
const {
4040
id,
4141
clearable,
42-
searchable,
4342
multi,
4443
options,
4544
setProps,
45+
search_value,
4646
style,
4747
loading_state,
4848
value,
@@ -122,7 +122,7 @@ const Dropdown = props => {
122122

123123
useEffect(() => {
124124
if (
125-
!searchable &&
125+
!search_value &&
126126
!isNil(sanitizedOptions) &&
127127
optionsCheck !== sanitizedOptions &&
128128
!isNil(value)

components/dash-core-components/tests/integration/dropdown/test_remove_option.py

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import json
22

3-
from dash import Dash, html, dcc, Output, Input
3+
import pytest
4+
5+
from dash import Dash, html, dcc, Output, Input, State
46
from dash.exceptions import PreventUpdate
57

68

@@ -11,7 +13,8 @@
1113
]
1214

1315

14-
def test_ddro001_remove_option_single(dash_dcc):
16+
@pytest.mark.parametrize("searchable", (True, False))
17+
def test_ddro001_remove_option_single(dash_dcc, searchable):
1518
dropdown_options = sample_dropdown_options
1619

1720
app = Dash(__name__)
@@ -22,7 +25,7 @@ def test_ddro001_remove_option_single(dash_dcc):
2225
dcc.Dropdown(
2326
options=dropdown_options,
2427
value=value,
25-
searchable=False,
28+
searchable=searchable,
2629
id="dropdown",
2730
),
2831
html.Button("Remove option", id="remove"),
@@ -38,18 +41,17 @@ def on_click(n_clicks):
3841

3942
@app.callback(Output("value-output", "children"), [Input("dropdown", "value")])
4043
def on_change(val):
41-
if not val:
42-
raise PreventUpdate
43-
return val or "None"
44+
return val or "Nothing Here"
4445

4546
dash_dcc.start_server(app)
4647
btn = dash_dcc.wait_for_element("#remove")
4748
btn.click()
4849

49-
dash_dcc.wait_for_text_to_equal("#value-output", "None")
50+
dash_dcc.wait_for_text_to_equal("#value-output", "Nothing Here")
5051

5152

52-
def test_ddro002_remove_option_multi(dash_dcc):
53+
@pytest.mark.parametrize("searchable", (True, False))
54+
def test_ddro002_remove_option_multi(dash_dcc, searchable):
5355
dropdown_options = sample_dropdown_options
5456

5557
app = Dash(__name__)
@@ -62,7 +64,7 @@ def test_ddro002_remove_option_multi(dash_dcc):
6264
value=value,
6365
multi=True,
6466
id="dropdown",
65-
searchable=False,
67+
searchable=searchable,
6668
),
6769
html.Button("Remove option", id="remove"),
6870
html.Div(id="value-output"),
@@ -84,3 +86,64 @@ def on_change(val):
8486
btn.click()
8587

8688
dash_dcc.wait_for_text_to_equal("#value-output", '["MTL"]')
89+
90+
91+
def test_ddro003_remove_option_multiple_dropdowns(dash_dcc):
92+
app = Dash(__name__)
93+
app.layout = html.Div(
94+
[
95+
dcc.Dropdown(
96+
id="available-options",
97+
multi=True,
98+
options=sample_dropdown_options,
99+
value=["MTL", "NYC", "SF"],
100+
),
101+
dcc.Dropdown(
102+
id="chosen",
103+
multi=True,
104+
options=sample_dropdown_options,
105+
value=["NYC", "SF"],
106+
),
107+
html.Button(id="remove-btn", children="Remove"),
108+
html.Button(id="submit-btn", children="Submit"),
109+
html.Div(id="value-output"),
110+
html.Div(id="options-output"),
111+
],
112+
)
113+
114+
@app.callback(
115+
Output("chosen", "options"),
116+
Input("available-options", "value"),
117+
)
118+
def update_options(available_options):
119+
if available_options is None:
120+
return []
121+
else:
122+
return [{"label": i, "value": i} for i in available_options]
123+
124+
@app.callback(
125+
Output("available-options", "options"), [Input("remove-btn", "n_clicks")]
126+
)
127+
def on_click(n_clicks):
128+
if not n_clicks:
129+
raise PreventUpdate
130+
return sample_dropdown_options[:-1]
131+
132+
@app.callback(
133+
[Output("value-output", "children"), Output("options-output", "children")],
134+
Input("submit-btn", "n_clicks"),
135+
State("chosen", "options"),
136+
State("chosen", "value"),
137+
)
138+
def print_value(n_clicks, options, value):
139+
if not n_clicks:
140+
raise PreventUpdate
141+
return [json.dumps(value), json.dumps([i["value"] for i in options])]
142+
143+
dash_dcc.start_server(app)
144+
btn = dash_dcc.wait_for_element("#remove-btn")
145+
btn.click()
146+
btn = dash_dcc.wait_for_element("#submit-btn")
147+
btn.click()
148+
dash_dcc.wait_for_text_to_equal("#value-output", '["NYC"]')
149+
dash_dcc.wait_for_text_to_equal("#options-output", '["MTL", "NYC"]')

0 commit comments

Comments
 (0)