Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Fix missing session when trying to display an error duing bookmarking. (#1984)

* Fixed `set()` method of `InputSelectize` controller so it clears existing selections before applying new values. (#2024)


## [1.4.0] - 2025-04-08

Expand Down
60 changes: 55 additions & 5 deletions shiny/playwright/controller/_input_controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -1187,21 +1187,71 @@ def set(
"""
Sets the selected option(s) of the input selectize.

Selected items are altered as follows:
1. Click on the selectize input to open the dropdown.
2. Starting from the first selected item, each position in the currently selected list should match `selected`. If the item is not a match, remove it and try again.
3. Add any remaining items in `selected` that are not currently selected by clicking on them in the dropdown.
4. Press the `"Escape"` key to close the dropdown.

Parameters
----------
selected
The value(s) of the selected option(s).
The [ordered] value(s) of the selected option(s).
timeout
The maximum time to wait for the selection to be set. Defaults to `None`.
"""
if isinstance(selected, str):
selected = [selected]
# Open the dropdown
self._loc_events.click()
for value in selected:
self._loc_selectize.locator(f"[data-value='{value}']").click(
timeout=timeout
)

# Sift through the selected items
# From left to right, we will remove ordered items that are not in the ordered `selected`
# If any selected items are not in the current selection, we will add them at the end
i = 0
while i < self._loc_events.locator("> .item").count():
item_loc = self._loc_events.locator("> .item").nth(i)
item_data_value = item_loc.get_attribute("data-value")

def delete_item(item_loc: Locator) -> None:
"""
Deletes the item by clicking on it and pressing the Delete key.
"""
item_loc.click()
self.page.keyboard.press("Delete")

# If the item has no data-value, remove it
if item_data_value is None:
delete_item(item_loc)
continue

# If there are more items than selected, we need to remove the extra ones
if i >= len(selected):
delete_item(item_loc)
continue

selected_data_value = selected[i]

# If the item is not the next `selected` value, remove it
if item_data_value != selected_data_value:
delete_item(item_loc)
continue

# The item is the next `selected` value
# Increment the index!
i += 1

# Add the remaining items
if i < len(selected):
for data_value in selected[i:]:
# Click on the item in the dropdown to select it
self._loc_selectize.locator(f"[data-value='{data_value}']").click(
timeout=timeout
)

# Close the dropdown
self._loc_events.press("Escape")
return

def expect_choices(
self,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from shiny import App, render, ui
from shiny.session import Inputs, Outputs, Session

app_ui = ui.page_fluid(
ui.input_selectize(
"test_selectize",
"Select",
["Choice 1", "Choice 2", "Choice 3", "Choice 4"],
multiple=True,
),
ui.output_text("test_selectize_output"),
)


def server(input: Inputs, output: Outputs, session: Session) -> None:
@render.text
def test_selectize_output():
return f"Selected: {', '.join(input.test_selectize())}"


app = App(app_ui, server)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from playwright.sync_api import Page

from shiny.playwright import controller
from shiny.pytest import create_app_fixture
from shiny.run import ShinyAppProc

app = create_app_fixture("app_selectize.py")


def test_inputselectize(page: Page, app: ShinyAppProc):
page.goto(app.url)

input_selectize = controller.InputSelectize(page, "test_selectize")
output_text = controller.OutputText(page, "test_selectize_output")

input_selectize.set(["Choice 1", "Choice 2", "Choice 3"])
output_text.expect_value("Selected: Choice 1, Choice 2, Choice 3")
input_selectize.set(["Choice 2", "Choice 3"])
output_text.expect_value("Selected: Choice 2, Choice 3")
input_selectize.set(["Choice 2"])
output_text.expect_value("Selected: Choice 2")
input_selectize.set(["Choice 2", "Choice 3"])
output_text.expect_value("Selected: Choice 2, Choice 3")
input_selectize.set(["Choice 1", "Choice 2"])
output_text.expect_value("Selected: Choice 1, Choice 2")
input_selectize.set([])
output_text.expect_value("Selected: ")
input_selectize.set(["Choice 1", "Choice 3"])
output_text.expect_value("Selected: Choice 1, Choice 3")
Loading