【发布时间】:2020-11-03 02:43:05
【问题描述】:
在尝试为this question 提出一个过于复杂的解决方案时,我偶然发现了以下问题。我有 2 个不同的模块,inputtable 显示 rhandsontable 并返回此表,resulttable 将此表作为输入,执行一些计算并将结果显示为 rhandsontable。 inputtable 返回 rhandsontable 对象作为反应值。因为每个模块可以有多个副本,所以我将来自inputtable 的结果存储在一个列表中,并将列表元素作为输入提供给resulttable。
我注意到在resulttable 中,反应输入input_data$input_table() 不能直接使用。当我在将反应值用于实际目的之前调用browser 或print 函数或将其分配给变量时,它就会起作用。否则我会得到错误
尝试应用非函数
据我了解,将响应式值传递给模块,这应该可以工作,而无需在使用之前对响应式值执行其他操作。如果我不使用列表来存储反应值,而只使用每个模块的一个副本并将inputtable 的结果直接存储在一个变量中并将其传递给resulttable,它会按我的预期工作。 (但将不同的反应值存储在 reactiveValues 对象中也会导致错误。)
有人知道那里发生了什么吗?
我为这个长示例道歉,当我尝试缩短它时,我丢失了错误:
library(shiny)
library(rhandsontable)
# define the first module
resulttableUI <- function(id) {
ns <- NS(id)
tabPanel(title = ns(id),
column(12,
rHandsontableOutput(ns("results_table"))))
}
resulttable <- function(id, input_data) {
moduleServer(
id,
function(input, output, session) {
# THE NEXT LINE NEEDS TO BE UNCOMMENTED TO MAKE IT WORK
# used_data <- input_data$input_table()
output$results_table <- renderRHandsontable({
rhandsontable(hot_to_r(input_data$input_table())[2:5]/hot_to_r(input_data$input_table())[1:4])
})
}
)
}
# define the second module
inputtableUI <- function(id) {
ns <- NS(id)
tabPanel(title = ns(id),
column(12,
rHandsontableOutput(ns("input_table"))))
}
inputtable <- function(id, i) {
moduleServer(
id,
function(input, output, session) {
output$input_table <- renderRHandsontable({
mat <- matrix(c(1:25) * i, ncol = 5, nrow = 5)
mat <- as.data.frame(mat)
rhandsontable(mat)
})
return(list(
input_table = reactive({input$input_table})
))
}
)
}
ui <- navbarPage("App",
tabPanel("Input",
numericInput('num_of_table', "Number of sub tabs: ", value = 1, min = 1, max = 10),
tabsetPanel(id = "insert_input")),
tabPanel("Results",
tabsetPanel(id = "insert_results"))
)
number_modules <- 0
current_id <- 1
server <- function(input, output, session) {
# variable to store the inputs from the modules
input_data <- list()
observeEvent(input$num_of_table, {
modules_to_add <- input$num_of_table - number_modules
for (i in seq_len(modules_to_add)) {
# add the logic for the input
input_data[[paste0("inputtable_", current_id)]] <<-
inputtable(paste0("inputtable_", current_id), current_id)
# add the logic for the results
resulttable(paste0("resulttable_", current_id),
input_data = input_data[[paste0("inputtable_", current_id)]])
# add the UI
appendTab(inputId = "insert_input",
tab = inputtableUI(paste0("inputtable_", current_id)))
appendTab(inputId = "insert_results",
tab = resulttableUI(paste0("resulttable_", current_id)))
# update the id
current_id <<- current_id + 1
}
number_modules <<- input$num_of_table
updateTabsetPanel(session,
"insert_input",
"inputtable_1-inputtable_1")
})
}
shinyApp(ui,server)
我正在使用R 3.6.1 和shiny 1.5.0。
很遗憾,还有另外两个问题:
- 你需要点击结果标签来渲染它
-
inputtable模块中的第一个显示表使用i = 2而不是i = 1,我还没有弄清楚为什么。
所以也许我的代码还有其他问题。对于这种奇怪的行为或如何制作一个更简单的例子,我很高兴。
【问题讨论】:
-
@Limey 感谢您的回复和链接。不幸的是,该链接仅指向您的答案列表,而不是特定答案。你能更新链接吗?谢谢
-
道歉。这是修改后的评论。我会删除原来的。您对
i == 2而不是i == 1的问题是因为反应式评估懒惰。当第一个选项卡评估时,i是2:因此你的问题。我对this post 的回答是相关的,我的回答中的链接指向一个干净可靠的实现,可以适应您的需求 -
@Limey 再次感谢您的回答。一些后续问题: 1.:我是否理解正确,因为惰性评估,需要一些时间才能评估选项卡,并且其余代码更快以至于
i已经是2?还是有其他一些机制在起作用(例如,在评估反应性之前,一些输入需要更改)? 2.:在您的解决方案here 中,您通过强制通过observe进行评估来规避问题? 3.:我最初的问题是否也可能与惰性评估反应的影响有关?
标签: r shiny shiny-reactivity rhandsontable shinymodules