【问题标题】:Unexpected output using `observeEvent`, `updateTabsetPanel` and nested modules使用 `observeEvent`、`updateTabsetPanel` 和嵌套模块的意外输出
【发布时间】:2020-12-28 17:55:30
【问题描述】:

我的应用程序有几个屏幕,我使用tabsetPanel() 处理它,隐藏选项卡标题(我 让它们在此处可见以进行调试)并使用updateTabsetPanel()选择它们

它从主屏幕开始(编码为mod_home_ui() / mod_home_server()) 你按下一个按钮来触发一个动作,会有几个但我在这里只留下一个,叫做“学习”(编码为mod_learn_ui()/mod_learn_server()

“学习”模块本身包含游戏,这里我只留下了两个游戏,为了简单起见,两个游戏都使用了相同的模块功能。 一个反应值panel_flag,决定了应该玩哪个游戏,这里我强制它为FALSE,这意味着应该玩游戏2。

这最后一步没有像我预期的那样工作,而消息显示代码通过了正确的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)

【问题讨论】:

  • app_server 中 mod_learn_server 的模块 ID 错误?
  • 谢谢@Victorp! YBS也在下面回答。您对如何避免或调试这些问题有任何提示吗?

标签: r shiny shiny-reactivity


【解决方案1】:

callModule(mod_learn_server, "learn_ui", learn = learn)

而不是

callModule(mod_learn_server, "home_ui", learn = learn)

应该修复它。

【讨论】:

  • 就是这样!维克多也发表了评论。我花了相当多的时间将一个更大的应用程序缩小到这个 reprex 并且在重读了这个代码 1000 次后仍然没有抓住它,尽管我觉得它会像事实证明的那样愚蠢。您知道避免这些问题或快速解决这些问题的任何技巧或方法吗?我觉得我可以一遍又一遍地犯这个错误,在更大的应用程序中总是需要时间来解决。
  • 我在模块设置方面不是很好。这就是我没有将我的大型闪亮应用程序转换为模块的原因。
【解决方案2】:

为了确保不再发生这种情况,我制作了一个包来测试闪亮代码的一致性,它的设计考虑了 {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'

我们发现:

在“mod_main_server”中,对callModule 的调用有一个模块参数mod_learn_server 和一个不以模块名称“learn”为前缀的id 参数“home_ui”

在“mod_main_ui”中,我们找到模块 id“learn_ui”,但在“mod_main_server”中找不到它

这将使调试变得微不足道。

https://github.com/moodymudskipper/shinycheck查看更多信息

【讨论】:

    猜你喜欢
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多