R Shiny 启用/禁用 UI 模块

Posted

技术标签:

【中文标题】R Shiny 启用/禁用 UI 模块【英文标题】:RShiny enable/disable UI modules 【发布时间】:2021-02-28 05:41:47 【问题描述】:

我想将我的 Shiny 应用设置为根据用户输入动态启用/禁用 UI 模块。我习惯于在非模块化应用程序中使用 ShinyJS 通过将 UI 元素的 ID 传递给 enable() 或 disable() 函数来执行此操作。但是,现在 UI 是在模块内部生成的,我无法再访问相同的 ID。

这里是一个示例应用程序,每次单击“counter1”按钮时递增 1。 “counterButton”功能包含在一个名为“counterModule.R”的外部模块中,我希望“toggleButton”在启用和禁用之间切换“counterButton”的状态。我认为目前对 toggleState() 的调用没有任何作用,因为找不到“counter1”ID。最好的解决方法是什么?

app.R

library(shiny)
library(shinyjs)


ui <- fluidPage(
  shinyjs::useShinyjs(), 
  mainPanel(actionButton(inputId = "toggleButton", label = "Toggle counter button"), 
  sidebarPanel(counterButton("counter1", "+1"))) 
)

server <- function(input, output, session) 
  observeEvent(input$toggleButton, 
    print("clicked toggle button")
    shinyjs::toggleState("counter1")
  )
  counterServer("counter1")


shinyApp(ui, server)

R/counterModule.R

counterButton <- function(id, label = "Counter") 
  ns <- NS(id)
  tagList(
      actionButton(ns("button"), label = label), 
      verbatimTextOutput(ns("out"))
  )


counterServer <- function(id) 
  moduleServer(
    id,
    function(input, output, session) 
      count <- reactiveVal(0)
      observeEvent(input$button, 
        count(count() + 1)
      )
      output$out <- renderText(
        count()
      )
      count
    
  )

【问题讨论】:

【参考方案1】:

你有两种可能性。闪亮模块的命名空间采用以下格式:namespace-elementid。这意味着您在模块中的按钮具有全局唯一的 id counter1-button(在模块内,您可以使用 button)。

因此,您可以在主 server 函数中使用命名空间 id:

observeEvent(input$toggleButton, 
    print("clicked toggle button")
    shinyjs::toggleState("counter1-button")
  )

但是,这以某种方式打破了模块和主服务器功能中定义的 ui/logic 的分离。因此,第二种选择是在主应用程序中定义切换按钮,但在模块中具有切换逻辑:

library(shiny)
library(shinyjs)

##########################
# code of the module
counterButton <- function(id, label = "Counter") 
  ns <- NS(id)
  tagList(
    actionButton(ns("button"), label = label), 
    verbatimTextOutput(ns("out"))
  )


counterServer <- function(id, toggle_action) 
  moduleServer(
    id,
    function(input, output, session) 
      count <- reactiveVal(0)
      observeEvent(input$button, 
        count(count() + 1)
      )
      output$out <- renderText(
        count()
      )
      
      observeEvent(toggle_action(), 
        print("clicked toggle button")
        shinyjs::toggleState("button")
      )
      
      count
    
  )



##########################
# code of the main app
ui <- fluidPage(
  shinyjs::useShinyjs(), 
  mainPanel(actionButton(inputId = "toggleButton", label = "Toggle counter button"), 
            sidebarPanel(counterButton("counter1", "+1"))) 
)

server <- function(input, output, session) 

  counterServer("counter1", toggle_action = reactive(input$toggleButton))


shinyApp(ui, server)

【讨论】:

感谢您的回复。了解模块命名空间的工作原理非常有帮助。在您的第二个代码块中,您建议在 app.R 文件中定义 UI 并处理模块中的切换功能,但是看起来所有内容都包含在一个文件中。我有点不清楚哪一部分代码进入 app.R 文件,哪一部分在 counterModule.R 文件中。你能把专门用于模块的代码部分分开吗? 查看我的编辑。您可以拥有一个包含模块代码的单独文件,也可以只有一个 app.R 文件,如我的答案中包含的应用程序和模块代码 太完美了,谢谢。我应该提到模块化我的应用程序的目标之一是减少 app.R 文件中的代码量。以这种方式将其分离出来将对代码的可读性有很大帮助。 肯定的。在 SO 上,我通常懒得把它分成不同的文件,但对于你的项目来说这完全有意义

以上是关于R Shiny 启用/禁用 UI 模块的主要内容,如果未能解决你的问题,请参考以下文章

R Shiny - 使用列排序禁用数据表中的特定行

如何通过脚本启用/禁用按钮组件?

如何在运行时启用/禁用“org.eclipse.ui.editors”扩展

Kendo UI TreeView动态启用/禁用dragAndDrop事件

element UI table 状态显示:禁用-启用 上架-下架

Jquery ui如何选择启用的选项卡?