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

huangapple go评论73阅读模式
英文:

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

问题

I'm completely new to modularizing in R Shiny using namespaces and I don't find it very intuitive. In the below code, broken into "Core App Code" and "Module Code", the reactive object iris1 is transmitted between the Core App Code and the Module Code, for use among several functions in the Module Code. The code uses parameters in the calls to the module server functions (and to their definitions). It assigns the value returned from one module to a reactive in the main server function, and then passes that reactive to the second module via the call to its server function.

The below seems to work EXCEPT that the customer header (a second header rendered in CSS in the myContainer function in the Module Code) that spans several columns, appearing above the DT table headers) does not work. What am I doing wrong in the below?

Code App Code:

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)

Module Code (saved as 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
    )
  })
}
英文:

I'm completely new to modularizing in R Shiny using namespaces and I don't find it very intuitive. In the below code, broken into "Core App Code" and "Module Code", the reactive object iris1 is transmitted between the Core App Code and the Module Code, for use among several functions in the Module Code. The code uses parameters in the calls to the module server functions (and to their definitions). It assigns the value returned from one module to a reactive in the main server function, and then passes that reactive to the second module via the call to its server function.

The below seems to work EXCEPT that the customer header (a second header rendered in CSS in the myContainer function in the Module Code) that spans several columns, appearing above the DT table headers) does not work. What am I doing wrong in the below?

Code App Code:

library(shiny)
library(DT)

source(&quot;C:/Users/.../my_module.R&quot;) 

ui &lt;- fluidPage(
  numericInput(&quot;number&quot;, label = &quot;Enter sepal length multiplier:&quot;, value = 1),
  DTOutput(&#39;tbl&#39;)
)

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

shinyApp(ui, server)

Module Code (saved as my_module.R):

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

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

my_module_ui &lt;- function(id) {
  ns &lt;- NS(id)
  DTOutput(ns(&quot;tbl&quot;))
}

my_module_server &lt;- function(input, output, session, iris1) {
  output$tbl &lt;- renderDT({
    renderTable(
      iris1()  # Access iris1 reactive object
    )
  })
}

答案1

得分: 3

以下是已经翻译好的部分:

这是一个模块化代码的工作示例。虽然你向你的代码添加了一个模块,但实际上你没有在使用它,也就是说,你的 tbl 输出是在主服务器中创建的,只有这个输出包含在主界面中。

相反,我将模块界面添加到了主界面,并从主服务器中删除了 output$tbl,以及相应的渲染函数。此外,由于 myContainer 只是一个函数,因此通过将表的名称作为参数传递,而不是依赖于在应用程序的不同部分定义的 reactive,使其自包含。

实际上,当我运行你的代码时,由于这个原因,我会遇到一个错误。另外,我看不到覆盖 shiny::renderTable 的必要性,并且如果需要自定义函数,我建议使用不同的名称来明确表示这一点。

最后,我切换到了使用 moduleServer 而不是使用 callModule 的新样式模块。

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)

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

英文:

Here is a working example of a modularized code. While you added a module to your code your are actually not using it, i.e. your tbl output is created in the main server and only this output is included in the main UI.

Instead I added the module UI to the main UI and dropped the output$tbl from the main server as well as the corresponding render function. Additionally, as myContainer is simply a function make it self contained by passing the names for your table as an argument instead of relying on a reactive defined in a different part of your app. Actually, when I run your code I get an error because of this. Also, I don't see any reason to overwrite shiny::renderTable with a custom function. If a custom function is needed I would suggest to make this clear by using a different name. Finally, I switched to the new style modules using moduleServer instead of using callModule.

library(shiny)
library(DT)

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

my_module_ui &lt;- function(id) {
  ns &lt;- NS(id)
  DTOutput(ns(&quot;tbl&quot;))
}

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

ui &lt;- fluidPage(
  numericInput(&quot;number&quot;, label = &quot;Enter sepal length multiplier:&quot;, value = 1),
  my_module_ui(&quot;myModule&quot;)
)

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

  my_module_server(&quot;myModule&quot;, iris1 = iris1)
}

shinyApp(ui, server)
#&gt; 
#&gt; Listening on http://127.0.0.1:3641

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

huangapple
  • 本文由 发表于 2023年6月6日 15:53:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76412494.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定