使用“observeEvent”、“updateTabsetPanel”和嵌套模块的意外输出
Unexpected output using `observeEvent`, `updateTabsetPanel` and nested modules
我的应用程序有多个屏幕,我使用 tabsetPanel()
处理它,隐藏选项卡 headers(我
让它们在此处可见以进行调试)并使用 updateTabsetPanel()
选择它们
它在主屏幕上启动(编码为 mod_home_ui()
/ mod_home_server()
)
你按下一个按钮来触发一个动作,会有几个但我只留下一个在这里,叫做“学习”(编码为 mod_learn_ui()
/ mod_learn_server()
)
“学习”模块本身包含游戏,这里我只留下两个游戏,为了简单起见,两者使用相同的模块功能。
一个反应值panel_flag
,决定应该玩哪个游戏,这里我强制它为FALSE
,这意味着应该玩game2。
这最后一步没有像我预期的那样工作,而消息显示代码通过了正确的 updateTabsetPanel()
调用,没有选择预期的选项卡,而且没有选择预期的文本显示在屏幕顶部。
这看起来像是一个命名空间问题,但我不明白我在这里做错了什么。
可以将下面的代码一次性复制粘贴到 运行 应用程序中,这是将发生的情况的 gif 动图:
# main ui and server
app_ui <- function() {
tagList(
fluidPage(
title = "My app",
tabsetPanel(
id = "switcher",
#type = "hidden",
selected = "home",
tabPanel("home", mod_home_ui("home_ui")),
tabPanel("learn", mod_learn_ui("learn_ui"))
)
)
)
}
app_server <- function(input, output,session) {
learn <- callModule(mod_home_server, "home_ui")
observeEvent(learn(), {
message("In app_server: observeEvent on learn() to switch to 'learn' panel")
updateTabsetPanel(session, "switcher", selected = "learn")
})
callModule(mod_learn_server, "home_ui", learn = learn)
}
# home module
mod_home_ui <- function(id){
ns <- NS(id)
tagList(
textOutput(ns("some_text")),
actionButton(ns("learn"), "learn")
)
}
mod_home_server <- function(input, output, session){
output$some_text <- renderText("I expect clicking on the above to trigger game2, not game1")
ns <- session$ns
reactive({
res <- req(input$learn)
message(
'In mod_home_server: returning req(input$learn) in mod_home_server to trigger learn()')
res
})
}
# learn module
mod_learn_ui <- function(id){
ns <- NS(id)
tabsetPanel(
id = ns("switcher"),
#type = "hidden",
tabPanel("game1", mod_game_ui(ns("game1_ui"))),
tabPanel("game2", mod_game_ui(ns("game2_ui")))
)
}
mod_learn_server <- function(input, output, session, learn){
ns <- session$ns
panel_flag <- eventReactive(learn(), {
message('In mod_learn_server: eventReactive on learn() to trigger relevant game')
# in reality this would be computed or random
FALSE
})
observeEvent(panel_flag(), {
message('In mod_learn_server: observeEvent on panel_flag()')
if (panel_flag()) {
message('In mod_learn_server: select "game1" panel')
updateTabsetPanel(session, "switcher", selected = "game1")
} else {
message('In mod_learn_server: select "game2" panel')
updateTabsetPanel(session, "switcher", selected = "game2")
}
})
callModule(mod_game_server, "game1_ui")
callModule(mod_game_server, "game2_ui")
}
# game module
mod_game_ui <- function(id){
ns <- NS(id)
tagList(
textOutput(ns("some_text")),
"I expect another line of text above this one"
)
}
mod_game_server <- function(input, output, session){
ns <- session$ns
output$some_text <- renderText("I expect this to be shown")
}
library(shiny)
shinyApp(app_ui, app_server)
callModule(mod_learn_server, "learn_ui", learn = learn)
而不是
callModule(mod_learn_server, "home_ui", learn = learn)
应该修复它。
为了确保这种情况不再发生,我制作了一个包来测试闪亮代码的一致性,它的设计考虑了 {golem} 框架和约定。
安装 remotes::install_github("moodymudskipper/shinycheck")
这是我在我的真实应用程序上 运行 shinycheck::check_shiny()
时得到的结果(与上面的略有不同):
shinycheck::check_shiny()
-----------------------------------------------------------------------
Check that all module scripts contain exactly 2 functions named appropriately
-----------------------------------------------------------------------
Check that all module ui functions use ns() or NS() on argument named id/inputId/outputId
-----------------------------------------------------------------------
Check that in ui, module ui functions, named `mod_MODULE_ui` refer to modules which exist and ids fed to them are prefixed with "MODULE_"
-----------------------------------------------------------------------
Check that ns() and NS() are never called in an argument that isn't id/inputId/outputId
-----------------------------------------------------------------------
Check that the module args of callModule are of the form "mod_MODULENAME_server", that there is an R file properly named for "MODULENAME", and that the id argument is prefixed by "MODULENAME_"
* In 'mod_main_server', a call to `callModule` has a module argument `mod_learn_server` and an `id` argument 'home_ui' that is not prefixed by the module name 'learn'
-----------------------------------------------------------------------
Check that modules and module ids mentionned on both ui and server side are consistent
* In 'mod_main_ui' we find the module id 'learn_ui' but we don't find it in 'mod_main_server'
我们发现:
In 'mod_main_server', a call to callModule
has a module argument mod_learn_server
and an id
argument 'home_ui' that is not prefixed by the module name 'learn'
In 'mod_main_ui' we find the module id 'learn_ui' but we don't find it in 'mod_main_server'
这将使调试变得微不足道。
查看更多
我的应用程序有多个屏幕,我使用 tabsetPanel()
处理它,隐藏选项卡 headers(我
让它们在此处可见以进行调试)并使用 updateTabsetPanel()
它在主屏幕上启动(编码为 mod_home_ui()
/ mod_home_server()
)
你按下一个按钮来触发一个动作,会有几个但我只留下一个在这里,叫做“学习”(编码为 mod_learn_ui()
/ mod_learn_server()
)
“学习”模块本身包含游戏,这里我只留下两个游戏,为了简单起见,两者使用相同的模块功能。
一个反应值panel_flag
,决定应该玩哪个游戏,这里我强制它为FALSE
,这意味着应该玩game2。
这最后一步没有像我预期的那样工作,而消息显示代码通过了正确的 updateTabsetPanel()
调用,没有选择预期的选项卡,而且没有选择预期的文本显示在屏幕顶部。
这看起来像是一个命名空间问题,但我不明白我在这里做错了什么。
可以将下面的代码一次性复制粘贴到 运行 应用程序中,这是将发生的情况的 gif 动图:
# main ui and server
app_ui <- function() {
tagList(
fluidPage(
title = "My app",
tabsetPanel(
id = "switcher",
#type = "hidden",
selected = "home",
tabPanel("home", mod_home_ui("home_ui")),
tabPanel("learn", mod_learn_ui("learn_ui"))
)
)
)
}
app_server <- function(input, output,session) {
learn <- callModule(mod_home_server, "home_ui")
observeEvent(learn(), {
message("In app_server: observeEvent on learn() to switch to 'learn' panel")
updateTabsetPanel(session, "switcher", selected = "learn")
})
callModule(mod_learn_server, "home_ui", learn = learn)
}
# home module
mod_home_ui <- function(id){
ns <- NS(id)
tagList(
textOutput(ns("some_text")),
actionButton(ns("learn"), "learn")
)
}
mod_home_server <- function(input, output, session){
output$some_text <- renderText("I expect clicking on the above to trigger game2, not game1")
ns <- session$ns
reactive({
res <- req(input$learn)
message(
'In mod_home_server: returning req(input$learn) in mod_home_server to trigger learn()')
res
})
}
# learn module
mod_learn_ui <- function(id){
ns <- NS(id)
tabsetPanel(
id = ns("switcher"),
#type = "hidden",
tabPanel("game1", mod_game_ui(ns("game1_ui"))),
tabPanel("game2", mod_game_ui(ns("game2_ui")))
)
}
mod_learn_server <- function(input, output, session, learn){
ns <- session$ns
panel_flag <- eventReactive(learn(), {
message('In mod_learn_server: eventReactive on learn() to trigger relevant game')
# in reality this would be computed or random
FALSE
})
observeEvent(panel_flag(), {
message('In mod_learn_server: observeEvent on panel_flag()')
if (panel_flag()) {
message('In mod_learn_server: select "game1" panel')
updateTabsetPanel(session, "switcher", selected = "game1")
} else {
message('In mod_learn_server: select "game2" panel')
updateTabsetPanel(session, "switcher", selected = "game2")
}
})
callModule(mod_game_server, "game1_ui")
callModule(mod_game_server, "game2_ui")
}
# game module
mod_game_ui <- function(id){
ns <- NS(id)
tagList(
textOutput(ns("some_text")),
"I expect another line of text above this one"
)
}
mod_game_server <- function(input, output, session){
ns <- session$ns
output$some_text <- renderText("I expect this to be shown")
}
library(shiny)
shinyApp(app_ui, app_server)
callModule(mod_learn_server, "learn_ui", learn = learn)
而不是
callModule(mod_learn_server, "home_ui", learn = learn)
应该修复它。
为了确保这种情况不再发生,我制作了一个包来测试闪亮代码的一致性,它的设计考虑了 {golem} 框架和约定。
安装 remotes::install_github("moodymudskipper/shinycheck")
这是我在我的真实应用程序上 运行 shinycheck::check_shiny()
时得到的结果(与上面的略有不同):
shinycheck::check_shiny()
-----------------------------------------------------------------------
Check that all module scripts contain exactly 2 functions named appropriately
-----------------------------------------------------------------------
Check that all module ui functions use ns() or NS() on argument named id/inputId/outputId
-----------------------------------------------------------------------
Check that in ui, module ui functions, named `mod_MODULE_ui` refer to modules which exist and ids fed to them are prefixed with "MODULE_"
-----------------------------------------------------------------------
Check that ns() and NS() are never called in an argument that isn't id/inputId/outputId
-----------------------------------------------------------------------
Check that the module args of callModule are of the form "mod_MODULENAME_server", that there is an R file properly named for "MODULENAME", and that the id argument is prefixed by "MODULENAME_"
* In 'mod_main_server', a call to `callModule` has a module argument `mod_learn_server` and an `id` argument 'home_ui' that is not prefixed by the module name 'learn'
-----------------------------------------------------------------------
Check that modules and module ids mentionned on both ui and server side are consistent
* In 'mod_main_ui' we find the module id 'learn_ui' but we don't find it in 'mod_main_server'
我们发现:
In 'mod_main_server', a call to
callModule
has a module argumentmod_learn_server
and anid
argument 'home_ui' that is not prefixed by the module name 'learn'
In 'mod_main_ui' we find the module id 'learn_ui' but we don't find it in 'mod_main_server'
这将使调试变得微不足道。
查看更多