1

I've got a an Rmarkdown file I want to display inside a shiny app, along with a download button to download it. Most of this works fine, but I've got a DT::datatable inside the Rmarkdown document. The datatable renders fine in the Rmarkdown once you download and open it, but the table doesn't show up inside the shiny app itself.

Is there a way I can get the datatable to show up inside the app as well? I don't want to use kable etc. because the download and filtering options with datatable are really useful.

Rmarkdown ("report.Rmd"):

---
title: "Example report"
output: html_document
params:
  n: NA
---

```{r}
# The `params` object is available in the document.
params$n
```

A plot of `params$n` random points.

```{r plot1}
plot(rnorm(params$n), rnorm(params$n))
```

```{r table1}
DT::datatable(iris, rownames = FALSE, 
                colnames = c("Sepal length", "Sepal width", "Petal length", "Petal width", "Species"), 
                extensions = 'Buttons',
                filter = "none",
                options = list(pageLength = 25, autowidth = TRUE,
                           dom = 'Blftip',                           
                           buttons = c('copy', 'csv', 'excel')))
```

Shiny app:

shinyApp(
    ui = fluidPage(
        sidebarLayout(
        sidebarPanel(
        sliderInput("slider", "Slider", 1, 100, 50),
        actionButton("generate_report", "Generate report")
        ),
        mainPanel(uiOutput("report"))
    )),
    server = function(input, output) {
    
        observeEvent(input$slider, {
            output$report <- renderUI(textOutput("holding_text"))
        })
        
        output$holding_text <- renderText("Please select inputs and click 'Generate report'")
        
        observeEvent(input$generate_report, {

            # Copy the report file to a temporary directory before processing it
            my_temp <- tempdir()
            
            tempReport <- file.path(my_temp, "report.Rmd")
            file.copy("report.Rmd", tempReport, overwrite = TRUE)
            
            # Set up parameters to pass to Rmd document
            params <- list(n = input$slider)
            
            # Knit the document, passing in the `params` list, and eval it in a
            # child of the global environment
            rmarkdown::render(tempReport,
                              params = params,
                              envir = new.env(parent = globalenv())
            )
            output$report <- renderUI({
                tagList(
                    downloadButton("download", "Download report"),
                    htmltools::HTML(includeHTML(file.path(my_temp, "report.html")))
                    
                )
            })
            
            output$download <- downloadHandler(
                # For PDF output, change this to "report.pdf"
                filename = "report.html",
                content = function(file) {
                    file.copy(file.path(my_temp, "report.html"), file)
                }
            )
        })
        
    }
)
user3757897
  • 316
  • 2
  • 13

1 Answers1

1

The problem is that Shiny doesn't execute JS when you call includeHTML, and DT needs it to render the tables.

There are 2 options:

  1. Include you file with the iframe tag (details here for example: https://stackoverflow.com/a/33021018/17518257), but it has some disadvantages (default height and width not always properly calculated, scroll issues, etc.).

  2. Render your DT directly in Shiny, which I find much cleaner. The disadvantage is that the report is now in 2 parts, the datatables and the rest. Here's how to do it.

First, store your DT in a variable before displaying it in the .Rmd file:

```{r table1}
dt_iris <- DT::datatable(iris, rownames = FALSE, 
                colnames = c("Sepal length", "Sepal width", "Petal length", "Petal width", "Species"), 
                extensions = 'Buttons',
                filter = "none",
                options = list(pageLength = 25, autowidth = TRUE,
                           dom = 'Blftip',                           
                           buttons = c('copy', 'csv', 'excel')))
dt_iris
```

Then, create you render environment for your Markdown before the render() call, to access the variable dt_iris later:

env <- new.env(parent = globalenv())
rmarkdown::render(tempReport,
                              params = params,
                              envir = env)
dt_iris <- env$dt_iris

Finally, display dt_iris with renderUI() and uiOutput():

ui <- fluidPage(
mainPanel(uiOutput("report"), uiOutput('dt'))

server <- function(input, output) {
output$report <- renderUI({
                tagList(
                    downloadButton("download", "Download report"),
                    htmltools::HTML(includeHTML(file.path(my_temp, "report.html")))
                    
                )
            })
output$dt <- renderUI({
                    htmltools::tagList(dt_iris)
                })
}
Tony
  • 66
  • 3