3

Say I have the following -- taking note of myList:

library(shiny)

myList <- list(
  first_element = tibble(a = 1, b = 2),
  second_element = tibble(a = 4:5, e = 7:8),
  third_element = tibble(a = c("one", "two", "three"), x = c("another", "another one", "another two"))
)

ui <- fluidPage(
  titlePanel("A Title"),
  verbatimTextOutput("pretty_output")
)

server <- function(input, output, session) {
  output$pretty_output <- renderPrint({
    myList
  })
}

shinyApp(ui, server)

This results in:

Shiny App

What I would like is to present myList as either individual renderTable or renderDataTable elements programmatically. The following illustrates a brute force approach, but I am looking for something a little more flexible, more D.R.Y., by leveraging a for loop, lapply, purrr::map(), and/or something else.

NOTE: The length of myList should be assumed to be unknown.

library(shiny)
library(DT)

myList <- list(
  first_element = tibble(a = 1, b = 2),
  second_element = tibble(a = 4:5, e = 7:8),
  third_element = tibble(a = c("one", "two", "three"), x = c("another", "another one", "another two"))
)

ui <- fluidPage(
  titlePanel("A Title"),
  dataTableOutput("dt_01"),
  dataTableOutput("dt_02"),
  dataTableOutput("dt_03")
)

server <- function(input, output, session) {
  output$dt_01 <- renderDataTable({
     datatable(myList[[1]], caption = names(myList[1]))
  })

  output$dt_02 <- renderDataTable({
    datatable(myList[[2]], caption = names(myList[2]))
  })

  output$dt_03 <- renderDataTable({
    datatable(myList[[3]], caption = names(myList[3]))
  })

}

shinyApp(ui, server)
JasonAizkalns
  • 20,243
  • 8
  • 57
  • 116

2 Answers2

4

Please check the following lapply approach:

library(shiny)
library(DT)

myList <- list(
  first_element = data.frame(a = 1, b = 2),
  second_element = data.frame(a = 4:5, e = 7:8),
  third_element = data.frame(a = c("one", "two", "three"), x = c("another", "another one", "another two"))
)

ui <- fluidPage(
  titlePanel("A Title"),
  uiOutput("tables")
)

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

  lapply(names(myList), function(x) {
    output[[x]] = renderDataTable({myList[[x]]})
  })

  output$tables <- renderUI({
    lapply(names(myList), dataTableOutput)
  })

}

shinyApp(ui, server)
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
1

So I think most approaches will involve renderUI, here's what I went with (which feels pretty elegant), but I will leave this unanswered for a bit to see if others can chime in. Code heavily-influenced by this post:

library(shiny)

myList <- list(
  first_element = tibble(a = 1, b = 2),
  second_element = tibble(a = 4:5, e = 7:8),
  third_element = tibble(a = c("one", "two", "three"), x = c("another", "another one", "another two"))
)

ui <- fluidPage(
  titlePanel("A Title"),
  uiOutput("tables")
)

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

  # Create the outputs dynamically
  output$tables <- renderUI({

    tableList <- imap(myList, ~ {
      tagList(
        h4(.y), # Note we can sprinkle in other UI elements
        tableOutput(outputId = paste0("table_", .y))
      )
    })

    tagList(tableList)
  })

  # Now render each output
  iwalk(myList, ~{
    output_name <- paste0("table_", .y)
    output[[output_name]] <- renderTable(.x)
  })

}

shinyApp(ui, server)

Shiny App

JasonAizkalns
  • 20,243
  • 8
  • 57
  • 116