Skip to content

Change parent from module with express #1841

@julibeg

Description

@julibeg

I would like to update a navset_bar from within modules in my Express app, but I can't seem to get it to work. The MWEs below have a navbar with several panels and I want each subsequent panel to contain a button that takes us back to the first panel. This works in Panel 2 (which is not a module), but does not work in the other panels (which are a module)

Naively, I tried

from shiny import reactive
from shiny.express import ui, input, module

ui.page_opts(title="Navset MWE", full_width=True, id="page")


@module
def other_panels(input, output, session, label):
    with ui.nav_panel(label):
        ui.input_action_button(
            "module_button", "Go back to Panel 1", cls="btn btn-primary"
        )

    @reactive.effect
    @reactive.event(input.module_button)
    def _():
        ui.update_navs("navbar", "Panel 1")


with ui.navset_bar(id="navbar", title=None):

    with ui.nav_panel("Panel 1"):
        ui.tags.p("hi")
    with ui.nav_panel("Panel 2"):
        ui.input_action_button(
            "back_to_1_from_p2", "Go back to Panel 1", cls="btn btn-primary"
        )
    other_panels("p3", label="Panel 3")
    other_panels("p4", label="Panel 4")


@reactive.effect
@reactive.event(input.back_to_1_from_p2)
def _():
    ui.update_navs("navbar", "Panel 1")

I assumed the parent namespace to be '' and thus the id "navbar" to be valid within the module as well, but looks like this is not the case.

I then tried to get it working by passing a callback, but no luck

from shiny import reactive
from shiny.express import ui, input, module

ui.page_opts(title="Navset MWE", full_width=True, id="page")


@module
def other_panels(input, output, session, label, callback):
    with ui.nav_panel(label):
        ui.input_action_button(
            "module_button", "Go back to Panel 1", cls="btn btn-primary"
        )

    @reactive.effect
    @reactive.event(input.module_button)
    def _():
        callback()


# put update into function that we can pass as a callback
def go_to_p1():
    print("going back to Panel 1")
    ui.update_navs("navbar", "Panel 1")


with ui.navset_bar(id="navbar", title=None):

    with ui.nav_panel("Panel 1"):
        ui.tags.p("hi")
    with ui.nav_panel("Panel 2"):
        ui.input_action_button(
            "back_to_1_from_p2", "Go back to Panel 1", cls="btn btn-primary"
        )
    other_panels("p3", label="Panel 3", callback=go_to_p1)
    other_panels("p4", label="Panel 4", callback=go_to_p1)


@reactive.effect
@reactive.event(input.back_to_1_from_p2)
def _():
    go_to_p1()

I've seen similar examples that work (e.g. #690), but they all use Core syntax and I couldn't get it working with Express. Any pointers are highly appreciated!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions