1

在尝试为这个问题提出一个过于复杂的解决方案时,我偶然发现了以下问题。我有 2 个不同的模块,inputtable显示rhandsontable并返回此表,并将resulttable此表作为输入,执行一些计算并将结果显示为rhandsontable. inputtablerhandsontable对象作为反应值返回。因为每个模块可以有多个副本,所以我将结果存储inputtable在一个列表中,并将列表元素作为输入提供给resulttable.

我注意到在 中resulttable,反应输入input_data$input_table()不能直接使用。当我在将反应值用于实际目的之前调用browserprint函数或将其分配给变量时,它就会起作用。否则我得到错误

尝试应用非功能

据我了解,将反应值传递给模块,这应该可以工作,而无需在使用它之前对反应值做其他事情。如果我不使用列表来存储反应值,而只使用每个模块的一个副本并将结果直接存储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.1shiny 1.5.0

不幸的是,还有另外两个问题:

  • 您需要单击结果选项卡来呈现它
  • 模块中第一个显示的表inputtable使用i = 2而不是i = 1,我还没有弄清楚为什么。

所以也许我的代码还有其他问题。对于这种奇怪的行为或如何制作一个更简单的例子,我很高兴。

4

1 回答 1

2

通过将forloop 更改为lapply,以及对服务器功能进行一些其他小的修改,我认为它可以工作。尝试这个

ui <- fluidPage(navbarPage("App",
                 
                 tabPanel("Input",
                          sliderInput('num_of_table', "Number of sub tabs: ", value = 1, min = 1, max = 10),
                          #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 <- 0

server <- function(input, output, session) {
  number_modules <- reactiveVal(0)
  # variable to store the inputs from the modules
  input_data <- list()
  
  observeEvent(input$num_of_table, {
    req(input$num_of_table)
    if (input$num_of_table > number_modules() ){
      modules_to_add <- reactive({input$num_of_table - number_modules()})
    }else {
      modules_to_add <- reactive({0})
    }
    lapply(1:modules_to_add(), function(i) {
      # update the id
      current_id <<- current_id + 1
      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
      if (input$num_of_table > number_modules() ){
        appendTab(inputId = "insert_input",
                  tab = inputtableUI(paste0("inputtable_", current_id)))
        appendTab(inputId = "insert_results",
                  tab = resulttableUI(paste0("resulttable_", current_id)))
      }
      
    })
    
    if (input$num_of_table > number_modules() ){
      number_modules(input$num_of_table)
      updateTabsetPanel(session,
                        "insert_input",
                        "inputtable_1-inputtable_1")
    }
    
  })
}

如果为 num_of_table 选择了较大的数字,它可能仍需要更新要显示的内容,因为输入表会显示所有子选项卡的最后一个表。

于 2020-07-14T05:11:51.227 回答