我在开发 Python 闪亮应用程序时遇到了一个特殊问题。我的应用程序当前具有通过按下名为“+”的导航集选项卡动态生成新选项卡的功能。但是,按“+”后,之前选项卡的状态(包括输入和输出值)将重置回空。有没有办法保留任何以前存在的选项卡的状态?
我的代码概述如下:
from shiny import App, Inputs, Outputs, Session, module, reactive, render, ui
# Create a Module UI
@module.ui
def textbox_ui(panelNum):
return ui.nav_panel(
f"Tab {panelNum}",
ui.input_text_area(id=f"test_text",
label = "Enter some text"),
ui.output_ui(f"display_text_{panelNum}"),
value = f"Tab_{panelNum}"
)
# Set up module server
@module.server
def textbox_server(input, output, session, panelNum):
@output(id=f"display_text_{panelNum}")
@render.text
def return_text():
return input[f"test_text"]()
# Set up app UI
app_ui = ui.page_fluid(
ui.tags.head(
ui.tags.style(
"""
body {
height: 100vh;
overflow-y: auto !important;
}
"""
)
),
ui.h2('Test App', align='center', fillable=True),
ui.output_ui("tab_UI"),
title = "Test App"
)
# Set up server
def server(input, output, session):
# Set up reactive values
navs = reactive.value(0)
# Add tabs if the user presses "+"
@reactive.effect
@reactive.event(input.shiny_tabs)
def add_tabs():
if input.shiny_tabs() == "+":
navs.set(navs.get() + 1)
@output
@render.ui
def tab_UI():
[textbox_server(str(x), panelNum=x+1) for x in range(navs.get())]
ui.update_navs("shiny_tabs", selected = f"Tab_{navs.get()}")
return ui.navset_tab(
ui.nav_panel("Home",
ui.card(
ui.card_header("Overview"),
ui.p("An example of the outputs clearing")
),
value = "panel0"
),
*[textbox_ui(str(x), panelNum=x+1) for x in range(navs.get())],
ui.nav_panel("+"),
id = "shiny_tabs"
)
app = App(app_ui, server)
问题在于,每次添加新选项卡时,都会重新创建所有选项卡及其相应的状态。为了保留状态,需要在选项卡外部存储每个选项卡的输入值。这可以使用
reactiveValues
或
reactiveVal
在 Shiny 会话中完成。
以下是使用
reactiveValues
修改后的代码:
from shiny import App, Inputs, Outputs, Session, module, reactive, render, ui
# Create a Module UI
@module.ui
def textbox_ui(panelNum):
return ui.nav_panel(
f"Tab {panelNum}",
ui.input_text_area(id=f"test_text_{panelNum}", label="Enter some text"),
ui.output_ui(f"display_text_{panelNum}"),
value=f"Tab_{panelNum}"
)
# Set up module server
@module.server
def textbox_server(input, output, session, panelNum, saved_values):
@reactive.effect
@reactive.event(input[f"test_text_{panelNum}"])
def save_input_value():
saved_values[panelNum] = input[f"test_text_{panelNum}"]()
@output(id=f"display_text_{panelNum}")
@render.text
def return_text():
return saved_values.get(panelNum, "")
# Set up app UI
app_ui = ui.page_fluid(
ui.tags.head(
ui.tags.style(
"""
body {
height: 100vh;
overflow-y: auto !important;
}
"""
)
),
ui.h2("Test App", align="center", fillable=True),
ui.output_ui("tab_UI"),
title="Test App"
)
# Set up server
def server(input, output, session):
# Set up reactive values
navs = reactive.value(0)
saved_values = reactive.Value({})
# Add tabs if the user presses "+"
@reactive.effect
@reactive.event(input.shiny_tabs)
def add_tabs():
if input.shiny_tabs() == "+":
navs.set(navs.get() + 1)
@output
@render.ui
def tab_UI():
ui.update_navs("shiny_tabs", selected=f"Tab_{navs.get()}")
return ui.navset_tab(
ui.nav_panel("Home",
ui.card(
ui.card_header("Overview"),
ui.p("An example of the outputs NOT clearing")
),
value="panel0"
),
*[textbox_ui(panelNum=x + 1) for x in range(navs.get())],
ui.nav_panel("+"),
id="shiny_tabs"
)
for i in range(1, navs.get() + 1):
textbox_server(panelNum=i, saved_values=saved_values)
app = App(app_ui, server)
更改如下:
-
为每个输入框使用唯一 ID:
我们将输入框的 ID 从
"test_text"
修改为"test_text_{panelNum}"
,以便每个选项卡都有唯一的 ID。 -
使用
reactive.Value
存储输入值: 我们创建了一个reactive.Value
对象 (saved_values
),用于存储每个选项卡的输入值。 -
在
textbox_server
中保存和加载输入值: 我们在textbox_server
中添加了逻辑,以便在输入框的值更改时,将其保存在saved_values
中,并在渲染输出时从saved_values
中加载值。
现在,即使添加了新选项卡,先前选项卡的输入和输出值也将被保留。
标签:python,py-shiny From: 78817794