Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to pass user inputs into R shiny modules

Tags:

r

shiny

I am working on a shiny app where on load it shows a default table. Have a user input which when I enter and click on run should update the table. And also when clicked on reset it should show the default table.As of now I am able to view the default table and nothing happens when I click on the run button.

optimzation <- function(input, output, session, data,budget,run,reset) {

  v <- reactiveValues(data = data)

  observeEvent(run, {
    v$data <- data %>% mutate(carb = mpg * budget)
  })

  observeEvent(reset, {
    v$data <- data # your default data
  })  

  output$mod_table <- DT::renderDataTable({
    DT::datatable(v$data, filter = "top")
  })
}

optimzationUI <- function(id) {
  ns <- NS(id)
  dataTableOutput(ns("mod_table"))

}

shinyApp(
    ui = basicPage(
      mainPanel(
        numericInput("budget_input", label = h5("Total Budget"), value = 9000000),
        actionButton("opt_run", "Run"),
        actionButton("opt_reset", "Reset"),
        tags$hr(),
        optimzationUI("optimize")
      )
    ),
    server = function(input, output) {
      demodata<-mtcars
      callModule(optimzation,"optimize", demodata,budget=input$budget_input,run=input$opt_run,reset = input$opt_reset)

    }
  )

Created on 2019-02-13 by the reprex package (v0.2.1.9000)

like image 599
SNT Avatar asked Feb 13 '19 18:02

SNT


2 Answers

It seems you need to be more careful when passing global user input to a shiny module. It seems it will "break" the reactivity. You can fix this my explicitly passing in a reactive object. Here's the updated module. Note the added () to get the current reactive value.

optimzation <- function(input, output, session, data, budget,run,reset) {

  v <- reactiveValues(data = data)

  observeEvent(run(), {
    v$data <- data %>% mutate(carb = mpg * budget())
  })

  observeEvent(reset(), {
    v$data <- data 
  })  

  output$mod_table <- DT::renderDataTable({
    DT::datatable(v$data, filter = "top")
  })
}

optimzationUI <- function(id) {
  ns <- NS(id)
  DT::dataTableOutput(ns("mod_table"))      
}

and here's the changed app. note the explicit reactive(input$....)

library(shiny)
library(dplyr)
shinyApp(
  ui = basicPage(
    mainPanel(
      numericInput("budget_input", label = h5("Total Budget"), value = 9000000),
      actionButton("opt_run", "Run"),
      actionButton("opt_reset", "Reset"),
      tags$hr(),
      optimzationUI("optimize")
    )
  ),
  server = function(input, output) {
    demodata<-mtcars
    callModule(optimzation,"optimize", 
               data=demodata,
               budget=reactive(input$budget_input),
               run=reactive(input$opt_run),
               reset = reactive(input$opt_reset))        
  }
)
like image 124
MrFlick Avatar answered Nov 06 '22 17:11

MrFlick


There are a few problems with your code that make it not reproducible currently: library(shiny) and library(dplyr) need to be added, and the dataTableOutput needs to be prefixed with DT::dataTableOutput.

The next problem (which is the actual question you're asking about) is that the values you're passing to the module are currently being passed as just regular values at one snapshot in time. They should be passed as reactives instead. It's a bit counter intuitive because we think of inputs as reactive, but when you pass input$reset then you're passing the module the specific value at this point in time. Instead, you need to pass it reactive(input$reset), and then in the module you access it with reset() instead of with reset. The same is true for the other reactives that are passed into the module.

Here's the complete code solution:

library(shiny)
library(dplyr)

optimzation <- function(input, output, session, data,budget,run,reset) {

  v <- reactiveValues(data = data)

  observeEvent(run(), {
    v$data <- data %>% mutate(carb = mpg * budget())
  })

  observeEvent(reset(), {
    v$data <- data # your default data
  })  

  output$mod_table <- DT::renderDataTable({
    DT::datatable(v$data, filter = "top")
  })
}

optimzationUI <- function(id) {
  ns <- NS(id)
  DT::dataTableOutput(ns("mod_table"))

}

shinyApp(
  ui = basicPage(
    mainPanel(
      numericInput("budget_input", label = h5("Total Budget"), value = 9000000),
      actionButton("opt_run", "Run"),
      actionButton("opt_reset", "Reset"),
      tags$hr(),
      optimzationUI("optimize")
    )
  ),
  server = function(input, output) {
    demodata<-mtcars
    callModule(optimzation,"optimize", demodata,
               budget = reactive(input$budget_input),
               run = reactive(input$opt_run),
               reset = reactive(input$opt_reset))

  }
)
like image 22
DeanAttali Avatar answered Nov 06 '22 17:11

DeanAttali