r shiny -shiny模块之间的inputId通信,以便使用shinyjs功能,如禁用/启用/切换

xbp102n0  于 2023-03-10  发布在  其他
关注(0)|答案(1)|浏览(145)

我一直在钻研Shiny模块,到目前为止,一切都很顺利。但是,我在处理来自另一个模块的inputId时遇到了麻烦。具体来说,我想使用shinyjs::disable这样的函数,通过按下一个模块中的按钮来禁用另一个模块中的按钮(numericInput、selectizeInput等也是如此)。
我考虑过使用R6,但考虑到它的简单性,它可能会给应用程序增加不必要的复杂性。尽管如此,我还是愿意接受涉及或不涉及R6/石像鬼方法的建议。
这里有一个玩具的例子,总结了这个问题和我已经尝试到目前为止。

selectUI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      column(width = 4, offset = 0, align = "center",
      selectizeInput(inputId = ns("item"), 
                     label = "selection",
                     choices = c("", "a", "b", "c"), 
                     selected = "")
      ),
      column(width = 8, offset = 0)
    )
  )
}

selectServer <- function(id) {
  moduleServer(
    id,
    function(input, output, session) {
      return (
        list(
          selection = shiny::reactive(input$item)
        )
      )
    }
  )
}

buttonUI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      column(width = 2, offset = 0, align = "center",
             circleButton(inputId = ns("btn"))
      ),
      column(width = 10, offset = 0)
    ))
}

buttonServer <- function(id, item) {
  moduleServer(
    id,
    function(input, output, session) {
      observeEvent(
        eventExpr = input$btn, 
        handlerExpr = {
          #' does not work, i've tried with item(), item()$inputId, item$inputId() 
          #' and also hardcoding the id with and without the ns prefix ("item", "select-item", "button-select-item")
          shinyjs::disable("item")  # the issue ----
        },
        ignoreNULL = TRUE,
        ignoreInit = TRUE
      )
      
      #'debug
      observe({
        #' input from module selectUI & selectServer identified correctly
        showNotification(item(), duration = 5) 
      })
    }
  )
}

library(shiny)
library(shinyjs)

ui <- fluidPage(
  useShinyjs(),
  selectUI(id = "select"),
  buttonUI(id = "button"),
)

server <- function(input, output, session) {
  
  item <- selectServer(id = "select")
  buttonServer(id = "button", item = item$selection)

}

shinyApp(ui, server)

欢迎提出任何意见或建议。

wgx48brx

wgx48brx1#

这里有一个使用gargoyle的解决方案,因为它是一个非常简单的解决方案,通常可以工作。gargoyle包只是一个很好的 Package 器,它围绕着session$userData对象中reactiveVal的使用。
另一种方法是将被动式从一个模块传递到另一个模块。这也可以很好地工作,但当你想像这里一样管理多个“更新信号”时(即当模块中的某个地方发生了什么事情时,禁用/启用UI的某些部分),这就成了一个问题。

selectUI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      column(width = 4, offset = 0, align = "center",
             selectizeInput(inputId = ns("item"), 
                            label = "selection",
                            choices = c("", "a", "b", "c"), 
                            selected = "")
      ),
      column(width = 8, offset = 0)
    )
  )
}

selectServer <- function(id) {
  moduleServer(
    id,
    function(input, output, session) {
      
      observeEvent(gargoyle::watch("disable_button"), ignoreInit = TRUE, {
        shinyjs::disable("item")
      })
      
      return (
        list(
          selection = shiny::reactive(input$item)
        )
      )
    }
  )
}

buttonUI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      column(width = 2, offset = 0, align = "center",
             circleButton(inputId = ns("btn"))
      ),
      column(width = 10, offset = 0)
    ))
}

buttonServer <- function(id, item) {
  moduleServer(
    id,
    function(input, output, session) {
      observeEvent(input$btn, {
        gargoyle::trigger("disable_button")
      })
      
      #'debug
      observe({
        #' input from module selectUI & selectServer identified correctly
        showNotification(item(), duration = 5) 
      })
      
    }
  )
}

library(shiny)
library(shinyjs)

ui <- fluidPage(
  useShinyjs(),
  
  selectUI(id = "select"),
  buttonUI(id = "button"),
)

server <- function(input, output, session) {
  
  gargoyle::init("disable_button")
  item <- selectServer(id = "select")
  buttonServer(id = "button", item = item$selection)
  
}

shinyApp(ui, server)

相关问题