posit-dev / py-shiny

Shiny for Python
https://shiny.posit.co/py/
MIT License
1.32k stars 81 forks source link

Updating choices does not preserve selected values in input_checkbox_group() #1752

Open schoulten opened 3 weeks ago

schoulten commented 3 weeks ago

I've noticed some unusual behavior in input_checkbox_group():

When I define a reactive effect to update the checkbox choices, the choices are updated in the UI as expected, but the new pre-selected choices are not applied.

Everything works fine if I don't include the reactive effect code. Am I missing something?

Reproducible code:

from shiny import App, ui, reactive

options = {
    "opt1": [5, 10, 15, 30, 60],
    "opt2": [5, 10, 20]
}

app_ui = ui.page_navbar(
    ui.nav_panel(
        "📊",        
        ui.layout_sidebar(
            ui.sidebar(
                ui.input_radio_buttons(
                    id = "aaa",
                    label = ui.strong("Label aaa:"),
                    choices = {"opt1": "Option 1", "opt2": "Option 2"},
                    selected = "opt1",
                    width = "100%"
                ),
                ui.input_checkbox_group(
                    id = "bbb",
                    label = ui.strong("Label bbb"),
                    choices = options["opt1"],
                    selected = options["opt1"],
                    inline = True,
                    width = "100%"
                )
            ),
            "Content"
        )
    ),
    title = ui.strong("Title"),
    fillable = True
)

def server(input, output, session):
    @reactive.effect
    def _():
        choice = input.aaa()
        ui.update_checkbox_group(
            id = "bbb", 
            choices = options[choice],
            selected = options[choice]
            )

app = App(app_ui, server)

Shinylive app demo:

https://shinylive.io/py/editor/#code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMAMwCdiYACAZwAsBLCbJjmVYnTJMAgujxMArhwl04UQmQ4A3OAB0IG4qiWkWTALxMQGpmaZqw2sgEZLiJsACsEmwAZXLpgGYPTAGxuALp4puaW1gBM9o5e7hKRwRoAvhoaaKgA+tKGUhxYUADmcJnQygBGUHQAFGFm0hhlmahQEHAANrUQ5j0WYIC8G4BTO5YSvWZ1vQ3tUNjEkmSZLBwAJnCVNRNj9flLq+tdW4d5GFyo85l0UMscxJnl82R6B0cvK7mWUJ8jmy+90+UdXINFhkBgQQq1MAAGSgAPaTE+UEQlgAlKFur9DoQ2MQOIQ4PojCYrDo7Eg+gB5HQ3bpkiQRHTRcmWKm6bpM5LozGHFgdOCKODLd4k2zfDHc3oAdxWZDYwvcbgApJYfi80aqjg1TudsfyANblYgAD0yhQYklQzwlPTeRks5QdYutf1hgKMwNBpAhlhhcKYDvKqK5zvM2Nx+MJTGsNJYwAZorAIQ1mN57X5FCFRmjejjIrJSfFIa47S4cFyABU6JI4MGQ0xpctZfK3EqVYXMSjk+Z1e2tpYAMKkCjkNuHTuFns9JRkNNAnae8GQ8scGfqMCT8w0Djtf6zoyV6saccaVY0VhwOiqGrasgSOZkM6388sJakFHIwsAATkCiUqgwcA0DQ6YTKeTCZNU74amGeJlkYN4YIikEag0FrLFAFCZLqhAGsaprmpaXZmLafQBiMFi9mMMERrk2YQLG1FwAWKZ8gKmZRtSOaMUERFMMe0DoLkYiWhk2QyOel4XiiYDJEEQA

gadenbuie commented 2 weeks ago

Thanks for the question @schoulten and for the reproducible example, which made it very easy to see your issue. Actually, in the shinylive.io example, I can see the type checker is trying to help you with red squiggles under the values provided to choices and selected in both ui.input_checkbox_group() and ui.update_checkbox_group(). There, an array of strings for both arguments is expected, so the following works as desired:

def server(input, output, session):
    @reactive.effect
    def _():
        choice = input.aaa()
        new_choices = [str(x) for x in options[choice]]
        ui.update_checkbox_group(
            id="bbb",
            choices=new_choices,
            selected=new_choices,
        )

That said, you're right that there's a difference between how this is handled by the input and update functions. In ui.update_checkbox_group(), selected must be a string to produce the desired result, whereas ui.input_checkbox_group() requests string arrays but at least coerces selected for you. We should look into this.

schoulten commented 2 weeks ago

Oh, now I see, thanks a lot!