Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Add search_value property to Dropdown #660

Merged
merged 11 commits into from
Sep 26, 2019
6 changes: 6 additions & 0 deletions src/components/Dropdown.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export default class Dropdown extends Component {
setProps({value});
}
}}
onInputChange={search_value => setProps({search_value})}
{...omit(['setProps', 'value'], this.props)}
/>
</div>
Expand Down Expand Up @@ -195,6 +196,11 @@ Dropdown.propTypes = {
*/
searchable: PropTypes.bool,

/**
* The value typed in the DropDown for searching.
*/
search_value: PropTypes.string,

/**
* Dash-assigned callback that gets fired when the input changes
*/
Expand Down
54 changes: 54 additions & 0 deletions tests/integration/dropdown/test_dynamic_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import dash
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import dash.testing.wait as wait
import dash_core_components as dcc


def test_ddsv001_dynamic_options(dash_duo):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I was not clear about the suggestion. the TCID added in the previous test should be unique. more details refer to Notes #2 in example. https://dash.plot.ly/testing

this one should be sth like dddo001

options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': 'Montreal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
]

app = dash.Dash(__name__)
app.layout = dcc.Dropdown(id="my-dynamic-dropdown", options=[])

@app.callback(
dash.dependencies.Output('my-dynamic-dropdown', 'options'),
[dash.dependencies.Input('my-dynamic-dropdown', 'search_value')],
)
def update_options(search_value):
if not search_value:
raise PreventUpdate
return [o for o in options if search_value in o['label']]

dash_duo.start_server(app)

# Get the inner input used for search value.
dropdown = dash_duo.find_element("#my-dynamic-dropdown")
input_ = dropdown.find_element_by_css_selector("input")

# Focus on the input to open the options menu
input_.send_keys("x")

#No options to be found with `x` in them, should show the empty message.
dash_duo.wait_for_text_to_equal(".Select-noresults", "No results found")

input_.clear()
input_.send_keys("o")
byronz marked this conversation as resolved.
Show resolved Hide resolved

options = dropdown.find_elements_by_css_selector(".VirtualizedSelectOption")

# Should show all options.
assert len(options) == 3

# Searching for `on`
input_.send_keys("n")

options = dropdown.find_elements_by_css_selector(".VirtualizedSelectOption")

assert len(options) == 1
print(options)
assert options[0].text == "Montreal"
28 changes: 28 additions & 0 deletions tests/integration/dropdown/test_search_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import dash
from dash.dependencies import Input, Output, State
import dash.testing.wait as wait
import dash_core_components as dcc
import dash_html_components as html


def test_ddsv001_search_value(dash_duo):
app = dash.Dash(__name__)
app.layout = html.Div(
[dcc.Dropdown(id="dropdown", search_value="something"), html.Div(id="output")]
)

@app.callback(
Output("output", "children"), inputs=[Input("dropdown", "search_value")]
)
def update_output(search_value):
return 'search_value="{}"'.format(search_value)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I missed this earlier - I think the test should use the same structure as the example app you gave, which is updating options from search_value in the same component. The reason this is important is (a) that's the primary use case for this prop, and (b) it will cause the dropdown to rerender, and we need to ensure that when it does the correct options are visible. I can certainly imagine errors in the component where on render it loses focus, or for some other reason it stops displaying the option list.

(BTW nota big deal but you can probably get rid of all the call_count stuff, that doesn't really matter for this test, we only care about what's going on within the browser)


dash_duo.start_server(app)

# Get the inner input used for search value.
input_ = dash_duo.find_element("#dropdown input")

dash_duo.wait_for_text_to_equal("#output", 'search_value="something"')

input_.send_keys("x")
dash_duo.wait_for_text_to_equal("#output", 'search_value="x"')
1 change: 1 addition & 0 deletions tests/unit/Dropdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('Props can be set properly', () => {
multi: false,
placeholder: 'pick something',
searchable: true,
search_value: "hello",
style: {backgroundColor: 'hotpink'},
loading_state: {
is_loading: false,
Expand Down