代码之家  ›  专栏  ›  技术社区  ›  TarJae

在一个闪亮的应用程序中模块化反应式表达式

  •  1
  • TarJae  · 技术社区  · 1 年前

    我目前正在重构我的Shiny应用程序,以利用模块来获得更好的结构和可维护性。该应用程序涉及一系列数字输入字段,这些字段的值相加并显示在标记为“ABC”的字段中。

    虽然应用程序在其初始非模块化状态下按预期运行,但在尝试将其重构为模块后,我遇到了反应性问题。具体来说,“ABC”字段应该显示所有输入字段的更新总和,但它并没有反应性地反映变化。

    我怀疑我可能没有在UI和服务器模块之间正确地传递参数,但我不确定如何解决这个问题。我将感谢任何帮助来改进和更正我的代码。非常感谢。“

    library(shiny)
    
    # Function to generate numericInputs
    createNumericInput <- function(region) {
      numericInput(region$id, region$label, min = 0, max = 3, step = 1, value = 0)
    }
    
    # List of inputs
    input_details <- list(
      list(id = "A1", label = "0 A"),
      list(id = "B2", label = "1 B"),
      list(id = "C3", label = "2 C")
    )
    
    # ui module
    name_UI <- function(id, numeric_inputs) {
      ns <- NS(id)
      tagList(
        tags$div(
          id = "inline",
          fluidRow(
            h4("ABC"),
            column(width = 6,
                   numeric_inputs,
                   numericInput(ns("ABC"), "ABC", min = 0, max = 39, step = 1, value = 0)
            )
          )
        )
      )
    }
    
    # server module
    name_server <- function(id, input_details) {
      moduleServer(id, function(input, output, session) {
        ns <- session$ns
        
        sum_reactive <- reactive({
          sum_values <- 0
          for(region in input_details) {
            input_id <- ns(region$id)
            val <- input[[input_id]]
            if (!is.null(val)) {
              sum_values <- sum_values + as.numeric(val)
            }
          }
          sum_values
        })
        
        # Update the value of ABC when the inputs change
        observe({
          updateNumericInput(session, ns("ABC"), value = sum_reactive())
        })
      })
    }
    
    # UI
    ui <- fluidPage(
      name_UI("mod_1", lapply(input_details, createNumericInput)) # Apply createNumericInput to input_details here
    )
    
    # Server logic
    server <- function(input, output, session) {
      name_server("mod_1", input_details)
    }
    
    # Run the app
    shinyApp(ui = ui, server = server)
    
    1 回复  |  直到 1 年前
        1
  •  2
  •   stefan    1 年前

    您的代码存在两个问题:

    1. 通过创建数字输入时 lapply 您没有处理模块的名称空间,即没有在模块名称空间中创建输入。为了解决这个问题,我添加了 ns 的论点 createNumericInput 。当然,我们可以简单地使用例如。 input[[region$id]] 以访问服务器中输入的值。使用 ns(...) 将不会产生任何效果,就像刚才所说的您没有在模块的命名空间中创建输入一样。

    2. 在服务器部分,在 updateNumericInput 您不必包装输入id ns() 或者正如哈德利所说 Mastering Shiny

      请注意 moduleServer() 自动处理名称空间。

    注意:我通过 lapply 在模块UI内部,并且只传递 input_details 列表添加到UI。

    library(shiny)
    
    # Function to generate numericInputs
    createNumericInput <- function(region, ns = NULL) {
      id <- if (!is.null(ns)) ns(region$id) else region$id
      numericInput(id, region$label, min = 0, max = 3, step = 1, value = 0)
    }
    
    # List of inputs
    input_details <- list(
      list(id = "A1", label = "0 A"),
      list(id = "B2", label = "1 B"),
      list(id = "C3", label = "2 C")
    )
    
    # ui module
    name_UI <- function(id, numeric_inputs) {
      ns <- NS(id)
      tagList(
        tags$div(
          id = "inline",
          fluidRow(
            h4("ABC"),
            column(
              width = 6,
              lapply(input_details, createNumericInput, ns = ns),
              numericInput(ns("ABC"), "ABC", min = 0, max = 39, step = 1, value = 0)
            )
          )
        )
      )
    }
    
    # server module
    name_server <- function(id, input_details) {
      moduleServer(id, function(input, output, session) {
        ns <- session$ns
    
        sum_reactive <- reactive({
          sum_values <- 0
          for (region in input_details) {
            val <- input[[region$id]]
            
            if (!is.null(val)) {
              sum_values <- sum_values + as.numeric(val)
            }
          }
          sum_values
        })
    
        observe({
          updateNumericInput(session, "ABC", value = sum_reactive())
        })
      })
    }
    
    # UI
    ui <- fluidPage(
      name_UI("mod_1", input_details) # Apply createNumericInput to input_details here
    )
    
    # Server logic
    server <- function(input, output, session) {
      name_server("mod_1", input_details)
    }
    
    # Run the app
    shinyApp(ui = ui, server = server)
    

    enter image description here