如何使用单独模块中的代码将自定义标题插入到使用 DT Shiny 渲染的表格中?

How to insert a custom header into a table rendered with DT Shiny with code from a separate module?

提问人:Curious Jorge - user9788072 提问时间:6/6/2023 更新时间:6/6/2023 访问量:38

问:

我对使用 namespaces 在 R Shiny 中进行模块化完全陌生,我发现它不是很直观。在下面的代码中,分为“核心应用代码”和“模块代码”,反应对象在核心应用代码和模块代码之间传输,以便在模块代码中的多个函数之间使用。该代码在对模块服务器函数(及其定义)的调用中使用参数。它将从一个模块返回的值分配给主服务器函数中的反应式,然后通过调用其服务器函数将该反应式传递给第二个模块。iris1

以下似乎有效,除了跨越几列的客户标头(在模块代码中的函数中以 CSS 呈现的第二个标头,出现在 DT 表标头上方)不起作用。我在下面做错了什么?myContainer

代码 应用代码:

library(shiny)
library(DT)

source("C:/Users/.../my_module.R") 

ui <- fluidPage(
  numericInput("number", label = "Enter sepal length multiplier:", value = 1),
  DTOutput('tbl')
)

server <- function(input, output) {
  iris1 <- reactive({
    tmp <- iris
    tmp$Sepal.Length <- tmp$Sepal.Length * input$number
    tmp
  })
  
  output$tbl <- renderDT({renderTable(iris1())})
  
  # Pass the reactive object iris1 to the module server function
  callModule(my_module_server, "myModule", iris1 = iris1)
}

shinyApp(ui, server)

模块代码(另存为my_module。R):

myContainer <- function() {
  htmltools::withTags(table(
    class = 'display',
    thead(
      tr(
        th(style = "border-top: none;border-bottom: none;"),
        th(colspan = 4, 'Lengths and widths',
           class = "dt-center",
           style = "border-right: solid 0.5px;border-left: solid 0.5px;border-top: solid 0.5px; background-color:#E6E6E6;"
        )
      ),
      tr(
        th(),
        lapply(names(iris1()), th)  # Access iris1 reactive object
      )
    )
  ))
}

renderTable <- function(data) {
  datatable(
    data,
    container = myContainer(),
    options = list(lengthChange = FALSE)
  )
}

my_module_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

my_module_server <- function(input, output, session, iris1) {
  output$tbl <- renderDT({
    renderTable(
      iris1()  # Access iris1 reactive object
    )
  })
}
CSS R Shiny 模块 命名空间

评论

1赞 Limey 6/6/2023
我只看到一个模块(带有服务器功能和 ui 功能)。其他人在哪里?您的反应是 .它没有“格式化”。格式设置与基础对象的演绎版相关联 (例如) ,因此您的自定义格式没有理由使用 “传输”。您的代码不可重现,因为我们无权访问您的驱动器。my_module_servermy_module_uiiris1data.framerenderTabledata.frameC:

答:

3赞 stefan 6/6/2023 #1

下面是一个模块化代码的工作示例。当您在代码中添加了一个模块时,您实际上并没有使用它,即您的输出是在主服务器中创建的,并且只有此输出包含在主 UI 中。tbl

取而代之的是,我将模块 UI 添加到主 UI 中,并从主服务器中删除了 以及相应的渲染功能。此外,作为一个函数,通过将表的名称作为参数传递,而不是依赖于在应用的不同部分中定义的表,使其自包含。实际上,当我运行您的代码时,因此我收到错误。另外,我认为没有任何理由用自定义函数覆盖。如果需要自定义函数,我建议使用不同的名称来明确这一点。最后,我切换到了新的样式模块,而不是使用 .output$tblmyContainerreactiveshiny::renderTablemoduleServercallModule

library(shiny)
library(DT)

myContainer <- function(x) {
  htmltools::withTags(table(
    class = "display",
    thead(
      tr(
        th(style = "border-top: none;border-bottom: none;"),
        th(
          colspan = 4, "Lengths and widths",
          class = "dt-center",
          style = "border-right: solid 0.5px;border-left: solid 0.5px;border-top: solid 0.5px; background-color:#E6E6E6;"
        )
      ),
      tr(
        th(),
        lapply(x, th)
      )
    )
  ))
}

my_module_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

my_module_server <- function(id, iris1) {
  moduleServer(id, function(input, output, session) {
    output$tbl <- renderDT({
      datatable(
        iris1(),
        container = myContainer(names(iris1())),
        options = list(lengthChange = FALSE)
      )
    })
  })
}

ui <- fluidPage(
  numericInput("number", label = "Enter sepal length multiplier:", value = 1),
  my_module_ui("myModule")
)

server <- function(input, output) {
  iris1 <- reactive({
    tmp <- iris
    tmp$Sepal.Length <- tmp$Sepal.Length * input$number
    tmp
  })

  my_module_server("myModule", iris1 = iris1)
}

shinyApp(ui, server)
#> 
#> Listening on http://127.0.0.1:3641

enter image description here

评论

1赞 Curious Jorge - user9788072 6/6/2023
是的,这很有效,您的解释非常有帮助。我能够将 、 和 分离到一个单独的文件中,并使用 从主 App 代码中获取它们。我开始通过这个简单的例子来理解模块和命名空间,谢谢。myContainermy_module_uimy_module_serversource("C:/Users/.../my_module.R")