Abhishek
Abhishek

Reputation: 437

how to read, display and download excel using modularized shiny app

All I am trying to do is read, render and download excel. Not sure how we can display specific UI details such as uploading excel button in dashboard sidebar and rendering and download button in dashboard body

Only error when I tried to get rid this error in mod_exampleUI module function. Error in mod_example("example_mod") : argument "output" is missing, with no default

Please find the code below

library(shiny)
library(magrittr) # Load magrittr for the piping operator %>%
library(DT)
library(readxl)
library(tidyselect)
library(writexl)
library(dplyr)
library(tidyr)
library(readxl)
library(stringr)
# Increase band width for shiny to handle bigger file 
options(shiny.maxRequestSize=300*1024^2) 

# Module UI to display sidebar content
mod_exampleUI <- function(id) {
  ns <- shiny::NS(id)
  shiny::tagList(

    fileInput(ns("file1"), "Choose XLSX File (Convert xls to xlsx)",accept=c(".xlsx")),
    tags$hr(),
    downloadButton(ns("downloadData"), "Download")
  )
}

# Module UI to display Body content
mod_example_displayUI <- function(id) {
  ns <- shiny::NS(id)
  shiny::tagList(
    DT::dataTableOutput(ns("contents"))
  )
}

# Function to read all excel sheet necessary
mod_example_display <- function(input, output, session) {
  output$contents <- DT::renderDataTable({
    DT::datatable(readxl::read_excel(input$file1$datapath)
                  ,options = list(pageLength = 7,scrollX = TRUE))
  })

  output$downloadData <- downloadHandler(
    filename = function() {
      paste("updated file dated-", Sys.Date(), ".xlsx")
    },

    content = function(file) {
      write_xlsx(DT::datatable(readxl::read_excel(input$file1$datapath),file))
    }
  )
}

ui <- fluidPage(

  shinydashboard::dashboardPage(
    skin = "yellow",
    # HEADER -----
    shinydashboard::dashboardHeader(
      title = "Modularizing App"
    ),
    # SIDEBAR -----
    shinydashboard::dashboardSidebar(
      shinydashboard::sidebarMenu(
        shinydashboard::menuItem('Example', tabName = 'example', icon = shiny::icon('file')),
        shinydashboard::tabItems(
          shinydashboard::tabItem("example", mod_exampleUI("example_sidemod"))
        )
      ) 
    ),
    # BODY -----
    shinydashboard::dashboardBody(
      shiny::tags$head(shiny::tags$link(rel = "stylesheet", type = "text/css", href = "custom.css")),
      shinydashboard::tabItems(
        shinydashboard::tabItem("example", mod_example_displayUI("example_bodymod"))
      )
    )
  )
)

server <- function(input, output) {
    shiny::callModule(mod_example_display, "mod_example")
}

shinyApp(ui,server)

Upvotes: 1

Views: 1360

Answers (1)

Abhishek
Abhishek

Reputation: 437

Pleased to share answer so that it might helkp other shiny developers. Although it is no elegant but mich appreciated if UI could be improved by experts.

library(shiny)
library(magrittr) # Load magrittr for the piping operator %>%
library(DT)
library(readxl)
library(tidyselect)
library(writexl)
library(dplyr)
library(tidyr)
library(readxl)
library(stringr)

# Increase band width for shiny to handle bigger file 
options(shiny.maxRequestSize=30*1024^2) 

# Function to read all excel sheet necessary
read_excel_allsheets <- function(filename, tibble = FALSE) {
  sheets <- readxl::excel_sheets(filename)
  x <- lapply(sheets, function(X) readxl::read_excel(filename, sheet = X, col_names = T, skip = 5
                                                     ,col_types = "text"
  ))
  if(!tibble) x <- lapply(x, as.data.frame)
  names(x) <- sheets
  x
}

# Module UI to read content
mod_readUI <- function(id) {
  ns <- shiny::NS(id)
  shiny::tagList(
    fileInput(ns("file1"), h6("Choose xlsx file")
              ,accept=c(".xlsx"))
  )
}

# Module UI to display content
mod_displayUI <- function(id) {
  ns <- shiny::NS(id)
  shiny::tagList(
    DT::dataTableOutput(ns("contents"))
  )
}

# Module UI to download content
mod_downloadUI <- function(id) {
  ns <- shiny::NS(id)
  shiny::tagList(
    downloadButton(ns("downloadData"), "Download")
  )
}

# Server functions
mod_display <- function(input, output, session, file) {
  # In case want to alter the data to download
  # myfile = reactive({as.data.frame(file()[,1])})
  output$contents <- DT::renderDataTable({
    DT::datatable(file()
                  ,options = list(pageLength = 7,scrollX = TRUE))
  })

  reactive({
    file()
    # myfile()
  })
}

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

  getData <- reactive({
    req(input$file1)
    inFile <- input$file1
    mysheets <- read_excel_allsheets(inFile$datapath)
    ppm <- mysheets$Download
    ppm
  })

  ### In ordert to send data as reactive 
  reactive({
    getData()
  })
}

mod_download <- function(input, output, session, displayData){

  output$downloadData <- downloadHandler(
    # browser(),
    filename = function() {
      paste("Updated file dated-", Sys.Date(), ".xlsx")
    },

    content = function(file) {
      write_xlsx(displayData(),file)
    }
  )

}

ui <- fluidPage(

  shinydashboard::dashboardPage(
    skin = "yellow",
    # HEADER -----
    shinydashboard::dashboardHeader(
      title = "Modularizing App"
    ),
    # SIDEBAR -----
    shinydashboard::dashboardSidebar(
      shinydashboard::sidebarMenu(id = "menu",
        shinydashboard::menuItem('Example', tabName = 'example', icon = shiny::icon('file')),

        conditionalPanel("input.menu == 'example'",
                         shinydashboard::menuSubItem(mod_readUI("sidemod")),
                         shinydashboard::menuSubItem(mod_downloadUI("downmod"))
        )
      ) 
    ),
    # BODY -----
    shinydashboard::dashboardBody(
      shinydashboard::tabItems(
        shinydashboard::tabItem("example", mod_displayUI("bodymod"))
      )
    )
  )
)

server <- function(input, output) {
  readFile <- shiny::callModule(mod_read, "sidemod")
  displayFile <- shiny::callModule(mod_display, "bodymod", file = readFile)
  shiny::callModule(mod_download, "downmod", displayFile)

}

shinyApp(ui,server)

Upvotes: 1

Related Questions