SNT
SNT

Reputation: 1403

Downloading powerpoint using R Shiny app in modules

I am trying to work on a functioniality for our shiny app where in the user can download a powerpoint with all the tables and charts. I did see a standalone app where I know how to use it if all the tables and plots are in the server component. Since our code base is increasing and we are trying to use modules to break the app I am unable to identify where should I have the downloadhandler. If I have it in the server component how can I pass my tables and plots from the modules to this function in server. Below is the code of a standalone download to powerpoint code.

library(shiny)
library(officer)
library(flextable)
library(dplyr)

my_table <- data.frame(
  Name = letters[1:4],
  Age = seq(20, 26, 2),
  Occupation = LETTERS[15:18],
  Income = c(50000, 20000, 30000, 45000)
)

ui <- fluidRow(
  column(
    width = 12,
    align = "center",
    tableOutput("data"),
    br(),
    downloadButton("download_powerpoint", "Download Data to PowerPoint")
  )
)

server <- function(input, output) {
  output$data <- renderTable({
    my_table
  })

  output$download_powerpoint <- downloadHandler(
    filename = function() {  
      "employee_data.pptx"
    },
    content = function(file) {
      flextable_prep <- flextable(my_table) %>% 
        colformat_num(col_keys = c("Age", "Income"), digits = 0) %>% 
        width(width = 1.25) %>% 
        height_all(height = 0.35) %>% 
        theme_zebra() %>% 
        align(align = "center", part = "all")

      example_pp <- read_pptx() %>% 
        add_slide(layout = "Title Slide", master = "Office Theme") %>% 
        ph_with_text(
          type = "ctrTitle",
          str = "Employee Data"
        ) %>% 
        ph_with(
          location = ph_location_type(type = "subTitle"),
          value = "Company 2019 Report"
        ) %>% 
        add_slide(layout = "Title and Content", master = "Office Theme") %>% 
        ph_with_text(
          type = "title",
          str = "2019 Data"
        ) %>% 
        ph_with_flextable_at(
          value = flextable_prep,
          left = 2.5,
          top = 2
        )

      print(example_pp, target = file)
    }
  )
}

shinyApp(ui, server)

Upvotes: 0

Views: 901

Answers (1)

Colin FAY
Colin FAY

Reputation: 5109

There are several ways to pass data from a module to another.

You can for example return a reactive from one module, and use it in another.

See (I removed the powerpoint generation here to focus on the implementation of the reactivity) :

library(shiny)
library(officer)
library(flextable)
library(dplyr)

showui <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns("table"), "table", choices = c("iris", "mtcars")),
    tableOutput(ns("data"))
  )
}

show <- function(input, output, session){
  ns <- session$ns

  my_table <- reactive({
    get(input$table)
  })

  output$data <- renderTable({
    head(my_table())
  })

  my_table
}


dlui <- function(id){
  ns <- NS(id)
  tagList(
    downloadButton(
      ns("download_powerpoint"), 
      "Download Data"
    )
  )
}

dl <- function(input, output, session, my_table){
  ns <- session$ns

  output$download_powerpoint <- downloadHandler(
    filename = function() {  
      "employee_data.csv"
    },
    content = function(file) {
      write.csv(my_table(), file)
    }
  )
}

ui <- fluidRow(
  column(
    width = 12,
    align = "center",
    showui("showui"),
    br(),
    dlui("dlui")
  )
)

server <- function(input, output) {

  my_table <- callModule(show, "showui")

  callModule(dl, "dlui", my_table)
}

shinyApp(ui, server)

Upvotes: 1

Related Questions