Reputation: 77
Good afternoon!
I'm trying to create a module, to be used in a shiny app, that will output both a graph and datatable that the user can interact with, the idea being that the user can create various scenarios that will then be evaluated/analysed. What I cannot wrap my head around is how to use the output of the module in the server code. I'm clearly doing something stupid but after two days I've run out of options and articles to read. This is my first exploration into modules.
I'm trying to reproduce this article (although I would prefer to show both input methods at once rather then use a button to swap between the two)
https://www.r-bloggers.com/2021/09/how-to-use-shinymatrix-and-plotly-graphs-as-inputs-in-a-shiny-app/
using DT::datatable similar to this
https://www.r-bloggers.com/2019/04/edit-datatables-in-r-shiny-app/
Here's a reprex of where I've got to, which isn't far (falling at the first hurdle!)... I'm trying to reuse the data produced by the module by rendering it and proving that I can use the data separately.
library(shiny)
library(tidyverse)
library(plotly)
library(DT)
library(shinydashboard)
#base data----
default_df <- structure(list(`0` = 70, `1` = 70, `2` = 70, `3` = 70, `4` = 70,
`5` = 70, `6` = 70, `7` = 70, `8` = 70, `9` = 70, `10` = 70,
`11` = 70, `12` = 70, `13` = 70, `14` = 70, `15` = 70, `16` = 70,
`17` = 70, `18` = 70, `19` = 70, `20` = 70, `21` = 70, `22` = 70,
`23` = 70), row.names = "calls", class = "data.frame")
#module----
##mod server----
mod_editable_srv <- function(id, data) {
moduleServer(id, function(input, output, session) {
x = data
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
x[i, j] <<- DT::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE) # important
print(x)
})
output$x1 = renderDT(x, selection = 'none', editable = TRUE)
return(x)
})
}
##mod ui----
mod_editable_ui <- function(id) {
tagList(
DT::dataTableOutput(NS(id, "x1")),
NS(id,"x")
)
}
#ui----
header <- dashboardHeader(title = "Density based clustering using file upload")
table <- column(width = 4,
box(width = 12, title = "Input hours",
mod_editable_ui('x1')
),
box(width = 12, title = "Input hours",
renderDT('test_dat')
)
)
body <- dashboardBody(table)
ui <- dashboardPage(
header,
dashboardSidebar(disable = TRUE),
body
)
#server----
server <- function(input, output) {
datafile <- mod_editable_srv("x1", default_df)
output$test_dat <- renderDataTable({
datafile()$x
})
}
#run app----
shinyApp(ui = ui, server = server)
I can see that the module is working(ish) by using the print debugging.
There seems to be a lot of tutorials around callModule patterns, but not much around moduleServer patterns. What there is also tend to leave out the server side of things, explaining how modules can move data between each other. As RStudio are not suggesting to use moduleServer I'd prefer to learn these patterns.
Any help would be greatly appreciated!
Upvotes: 0
Views: 1689
Reputation: 20329
Here's a try to explain how to use the return value(s) of modules in the main app. In this toy example, the main app defines a global numeric y
which is passed down to the modules. The module in turn defines another numeric x
and return the sum and the product respectively.
library(shiny)
rows <- 1:2
sample_ui <- function(id, idx = 1) {
ns <- NS(id)
fluidRow(numericInput(ns("x"), paste0("x_", idx), 10, 1, 100))
}
sample_server <- function(id, y) {
moduleServer(id, function(input, output, session) {
add <- reactive(input$x + y())
multiply <- reactive(input$x * y())
list(add = add, multiply = multiply)
})
}
ui <- fluidPage(fluidRow(numericInput("y", "y", 1, 1, 10)),
lapply(rows, function(i) sample_ui(paste0("x", i), i)),
fluidRow(verbatimTextOutput("out")))
server <- function(input, output, session) {
get_y <- reactive(req(input$y))
hdl <- lapply(paste0("x", rows), sample_server, get_y)
output$out <- renderPrint({
## this would be normally also a loop, but to illustrate I define it explicitely
## lapply(hdl, function(h) c(add = h$add(), mult = h$multiply()))
list(c(add = hdl[[1]]$add(),
mult = hdl[[1]]$multiply()),
c(add = hdl[[2]]$add(),
mult = hdl[[2]]$multiply()))
})
}
shinyApp(ui, server)
Upvotes: 1