2

The package embed a Shiny app together with a dataset. The package source is on GitHub.

The embedded dataset is used to populate the ui (field Input1) and the dataset (in data/data_test.rda, dataframe with 3 fields {year_p, model_p, volume_p}) load in a lazy manner when the package is loaded (description file parameter LazyData set at true).

This data stays identical the whole session, so I don't want to make a reactive function for it. The issue is that if I'm using the dataset to populate the ui, the package won't build and will generate an error when building

The alternatives I considered are:

  1. to have a reactive function (model_reactive()) and an observeEvent/updateSelectInput defined in server.R, but this really seems inefficient. BTW, is there a way to have the reactive function to compute only once ?

  2. place the code manipulating the dataset in global.R in order the data is available for server.R and ui.R

  3. Maybe this post explains how to do with the environment, but I didn't get it.

ui.R

r shiny::selectInput("Input1", "Input1:", choices = model_ls, multiple = F, selectize = F) # error when building the package # ERROR: lazy loading failed for package 'TESTshinyapp'

server.R

r model_ls <- input_model(dat)

input.R

r input_model <- function(data) {dplyr::select(data, model_p) %>% dplyr::distinct() %>% unlist()}

Fabien N.
  • 35
  • 5

1 Answers1

2

The root of the problem is that you dataset data_test is out of scope when the functions of your package are parsed. This behavior is expected and most packages get around this by using functions that dynamically load the dataset as needed.

A simple workaround is doing exactly this: defining the app's ui as a function

library(shiny)

ui <- function() {
  data(data_test, package = "TESTshinyapp")
  fluidPage(
    "Names of the dataset: ", 
    paste(names(data_test), collapse = ", ")
  )
}

server <- function(input, output, session) {

}

shinyApp(ui(), server)

This way, the data will be loaded dynamically when the app starts just like it is in the server. (NOTE: In your actual package, sidebar also needs to be converted into a function to make this work.)

Another possibility is to load the data in launchApp and then create ui and server with a factory pattern. In other words: the dataset is put into scope in launchApp and then passed as an argument to the factories.

server_factory <- function(myData) {
  function(input, output, session) {
    ## use myData here as you please
  }
}

ui_factory <- function(myData) {
  fluidPage(
    "Names of the dataset: ", 
    paste(names(myData), collapse = ", ")
  )
}

launchApp <- function() {
  data(data_test, package = "TESTshinyapp")

  shinyApp(
    ui_factory(data_test),
    server_factory(data_test)
  )
}

launchApp()

This pattern also allows you to define parameters for launchApp and pass them down to the factories if you want.

Gregor de Cillia
  • 7,397
  • 1
  • 26
  • 43
  • This solved my issue, and the explanation is clear (thanks Gregor). I found more about function factories in [Advanced R](https://adv-r.hadley.nz/function-factories.html). – Fabien N. Nov 28 '18 at 08:47