英文:
r shiny - communication of inputId between shiny modules in order to use shinyjs functions like disable/enable/toggle
问题
I've been delving into Shiny modules, and so far, everything has been going well. However, I'm having trouble manipulating inputIds that come from another module. Specifically, I want to use functions like shinyjs::disable to disable a button in one Shiny module by pressing a button in another module (same applies for numericInput, selectizeInput, etc).
I've considered using R6, but it may add unnecessary complexity to the app, given its simplicity. Nonetheless, I'm open to suggestions that involve or do not involve an R6/gargoyle approach.
Here is a toy example that summarizes the issue and what I've tried so far.
(以下为代码部分)
Any comments or suggestions are welcome.
英文:
I've been delving into Shiny modules, and so far, everything has been going well. However, I'm having trouble manipulating inputIds that come from another module. Specifically, I want to use functions like shinyjs::disable to disable a button in one Shiny module by pressing a button in another module (same applies for numericInput, selectizeInput, etc).
I've considered using R6, but it may add unnecessary complexity to the app, given its simplicity. Nonetheless, I'm open to suggestions that involve or do not involve an R6/gargoyle approach.
Here is a toy example that summarises the issue and what I've tried so far.
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)
Any comments or suggestions are welcome.
答案1
得分: 1
以下是翻译好的内容:
这里有一个解决方案,它确实使用了 gargoyle
,因为这是一个通常有效的简单解决方案。gargoyle
包只是对在 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")
})
# 调试
observe({
# 来自模块 selectUI 和 selectServer 的输入正确识别
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)
英文:
Here is a solution that does use gargoyle
, because it is such a simple solution that will work generally. The gargoyle
package is just a nice wrapper around the use of reactiveVal
's inside the session$userData
object.
The alternative would be to pass reactives from one module to another. That will work fine too but becomes a problem when you want to manage multiple 'update signals' like you are doing here (i.e. disable/enable parts of the UI when something happens in a module, somewhere).
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论