RenderTable function behaving unusually in loop

Viewed 67

See the code below - what should happen is, when you press the button, it displays table1 and table2, but what actually happens is you get table2 twice.

It works correctly if you write out both statements without the loop, but this isn't an option for my actual app. Have also tried isolate(i) (even though it's not reactive).

How can I get this to work?

library(shiny)

ui <- fluidPage(
  tableOutput("test1"),
  tableOutput("test2"),
  actionButton("button", "Press me!")
)

server <- function(input, output, session) {
  tables <- list(table1 = data.frame(a = 1:4, b = 1:4), table2 = data.frame(c = 5:8, d = 5:8))
  
  observeEvent(input$button, {
    for(i in 1:2) {
      output[[paste0("test", i)]] <- renderTable(tables[[paste0("table", i)]])
    }
  })
}

shinyApp(ui, server)
1 Answers

You're a victim of R's lazy evaulation. for evaluates lazily, so when the outputs are rendered, i is 2 for both outputs. lapply forces evaluation, so this gives you what you want:

library(shiny)

ui <- fluidPage(
  tableOutput("test1"),
  tableOutput("test2"),
  actionButton("button", "Press me!")
)

server <- function(input, output, session) {
  tables <- list(table1 = data.frame(a = 1:4, b = 1:4), table2 = data.frame(c = 5:8, d = 5:8))
  
  observeEvent(input$button, {
    lapply(
      1:2,
      function(i) output[[paste0("test", i)]] <- renderTable(tables[[paste0("table", i)]])
    )
  })
}

shinyApp(ui, server)

Thank you for taking the effort to produce an appropriate MWE. Not many do.

EDIT

Another option, which is longer but perhaps more transparent and adaptable, is simply to reference the button within the renderer for each table:

library(shiny)

ui <- fluidPage(
  tableOutput("test1"),
  tableOutput("test2"),
  actionButton("button", "Press me!")
)

server <- function(input, output, session) {
  tables <- list(table1 = data.frame(a = 1:4, b = 1:4), table2 = data.frame(c = 5:8, d = 5:8))
  
  output$test1 <- renderTable({
    if (input$button > 0) {
      tables$table1
    }
  })
  
  output$test2 <- renderTable({
    if (input$button > 0) {
      tables$table2
    }
  })
}

shinyApp(ui, server)
Related