3

I am trying to adapt R Shiny: automatically refreshing a main panel without using a refresh button to a new minimal working example:

ui <- fluidPage(

  pageWithSidebar(
    headerPanel("actionButton test"),
    sidebarPanel(
      numericInput("n", "N:", min = 0, max = 100, value = 50),
      br(),
      actionButton("goButton", "Go!"),
      p("Click the button to update the value displayed in the main panel."),
      actionButton("newButton", "New Button"),
      actionButton("newButton2", "Another New Button")
    ),
    mainPanel(
      verbatimTextOutput("nText"),
      textOutput("some_text_description"),
      plotOutput("some_plot")
    )
  )

)


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

  # builds a reactive expression that only invalidates 
  # when the value of input$goButton becomes out of date 
  # (i.e., when the button is pressed)
  ntext <- eventReactive(input$goButton, {
    input$n
  })

  output$nText <- renderText({
    ntext()
  })


  # Prep some text for output
  output$some_text_description <- renderText({ 
    if (input$newButton == 0) {return(NULL)}
    else { 
      "Lorem ipsum dolorom." 
    }
  })

  # Prep some figure for output
  # Simple Bar Plot 
  output$some_plot <- renderPlot({ 
    if (input$newButton2 == 0) {return(NULL)}
    else { 
      counts <- table(mtcars$gear)
      barplot(counts, main="Car Distribution", xlab="Number of Gears")
    }
  })

}



shinyApp(ui = ui, server = server)

In the code above, I have three actionButton commands, one which produces a plot, one which produces text output, and one which produces a number (as verbatim text output). As you click through each button, new output appears alongside previously generated output (from the last button you pressed).

Without needing to implement a refresh button that clears everything manually, how do I get each actionButton to override (i.e., wipe) the output of the others automatically without them all stacking atop of each other in the main panel. My understanding is that I need to use some combination of observeEvent, NULL, and reactiveValues but my attempts have so far been unsuccessful.

warship
  • 2,924
  • 6
  • 39
  • 65

1 Answers1

3

You can use renderUI() for that.

  output$all <- renderUI({
    global$out
  })

Within a global reactiveValue global$out you can store which ui element you would like to display. (Initially it should be empty, therefore NULL).

  global <- reactiveValues(out = NULL)

And then listen for the clicks in the Buttons and update global$out accordingly.

  observeEvent(input$goButton, {
    global$out <- verbatimTextOutput("nText")
  })

  observeEvent(input$newButton, {
    global$out <- textOutput("some_text_description")
  })

  observeEvent(input$newButton2, {
    global$out <- plotOutput("some_plot")
  })

Full app would read:

library(shiny)
ui <- fluidPage(

  pageWithSidebar(
    headerPanel("actionButton test"),
    sidebarPanel(
      numericInput("n", "N:", min = 0, max = 100, value = 50),
      br(),
      actionButton("goButton", "Go!"),
      p("Click the button to update the value displayed in the main panel."),
      actionButton("newButton", "New Button"),
      actionButton("newButton2", "Another New Button")
    ),
    mainPanel(
      uiOutput("all")
    )
  )

)


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

  global <- reactiveValues(out = NULL)

  observeEvent(input$goButton, {
    global$out <- verbatimTextOutput("nText")
  })

  observeEvent(input$newButton, {
    global$out <- textOutput("some_text_description")
  })

  observeEvent(input$newButton2, {
    global$out <- plotOutput("some_plot")
  })

  output$all <- renderUI({
    global$out
  })

  output$nText <- renderText({
    input$n
  })

  output$some_text_description <- renderText({ 
      "Lorem ipsum dolorom."
  })

  # Simple Bar Plot 
  output$some_plot <- renderPlot({ 
    counts <- table(mtcars$gear)
    barplot(counts, main="Car Distribution", xlab="Number of Gears")
  })

}



shinyApp(ui = ui, server = server)
Tonio Liebrand
  • 17,189
  • 4
  • 39
  • 59