英文:
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("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
)
})
}
答案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)
英文:
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 <- 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论