user1997567
user1997567

Reputation: 439

Modularizing Shiny R app code

I am trying to separate the functionality of my Shiny application in order to make it reusable.

I have my ui. R file where I define :

tabPanel("Unemployed", source("unemployed_select.R", local=TRUE)$value),

and in my unemployed_select.R I define:

fluidPage(
titlePanel("Basic DataTable"),

# Create a new Row in the UI for selectInputs
fluidRow(
column(4,
       selectInput("man",
                   "Manufacturer:",
                   c("All",
                     unique(as.character(mpg$manufacturer))))
),
column(4,
       selectInput("trans",
                   "Transmission:",
                   c("All",
                     unique(as.character(mpg$trans))))
),
column(4,
       selectInput("cyl",
                   "Cylinders:",
                   c("All",
                     unique(as.character(mpg$cyl))))
)
),
# Create a new row for the table.
fluidRow(
DT::dataTableOutput("table")
)
)

My server.R file is :

library(shiny)
library(shinythemes)
library(dataset)

shinyServer(function(input, output) {

# Filter data based on selections
output$table <- DT::renderDataTable(DT::datatable({
data <- mpg
if (input$man != "All") {
  data <- data[data$manufacturer == input$man,]
}
if (input$cyl != "All") {
  data <- data[data$cyl == input$cyl,]
}
if (input$trans != "All") {
  data <- data[data$trans == input$trans,]
}
data
}))


})    

I used the code from a well-known example in R gallery https://shiny.rstudio.com/gallery/basic-datatable.html

just to be sure that have no problems of data. Still datatable is not rendering so I guess it has to be a problem with defining inside source file unemployed_select.R.

Any ideas?

Regards

Upvotes: 1

Views: 1201

Answers (1)

Farhan Kathawala
Farhan Kathawala

Reputation: 271

You are right that you need to use source() to load your module file, but with Shiny, you need to be aware of namespaces. The module and the file it is sourced in must share a namespace, wherein names for things are shared. For example, in your module code, you have this line:

column(4,
   selectInput("man",
               "Manufacturer:",
               c("All",
                 unique(as.character(mpg$manufacturer))))

But you want the module to share the namespace of the file it is included in, so you need to have a way to let the file, which is including the module, know which parts are ids, like "man" and which parts are serious arguments like "Manufacturer:"

So in a Shiny Module, that line would become

column(4,
   selectInput(ns("man"),
               "Manufacturer:",
               c("All",
                 unique(as.character(mpg$manufacturer))))

Here the ns() function is used to include the id in the namespace, this will allow your declared id "man" to be usable by the rest of the app.

There is a great guide to namespaces and writing modules in Shiny here:

https://shiny.rstudio.com/articles/modules.html

The link above points out that you must namespace ids, must make your module fit into a function and call that function using callModule() from your ui.R file, and must wrap everything in a tagList instead of a fluidPage.

Best of luck!

Upvotes: 1

Related Questions