Modularized Shiny app: 如何下载模块之间传递的数据集

问题描述 投票:0回答:1

背景

我想在模块之间传递一个数据集(以下代表中的

iris
)。一旦通过,我想点击一个按钮来下载数据集。 我无法下载数据集。它是一个更大的应用程序的一部分,所以我想在 reprex 中尽可能保持一致。例如,我想继续使用 bs4Dash,但我也想保持文件结构不变。这也适用于
boxDropdown()
boxDropdownItem()
的使用。根据他们的 documentation here 如果我传递一个
id
参数,它将表现为一个
actionButton()
,因此我没有为
actionButton()
使用明确的
downloadHandler()
。在下面的 reprex 中,我添加了打印语句来跟踪和验证该过程。我曾尝试从模块服务器返回一个值(例如 seen here),但这没有用。所以我创建了这个代表来帮助调试它。

文件结构

app/
├── global.R
├── server.R
├── ui.R
└── modules/

app/modules
├── first_module.R
└── second_module.R

代表

要测试 reprex,请运行

global.R
。我正在尝试解决数据未下载的问题。

全球.R
# Load necessary libraries
require(shiny)
require(bs4Dash)

# Source the modules
source(file = "modules/second_module.R", local = TRUE)
source(file = "modules/first_module.R", local = TRUE)
服务器.R
# Define the server for the Shiny app
## This isn't necessarily needed with the use of moduleServer()
## Included here in case the file is needed in the codebase
server <- function(input, output, session) {
  
  # Call the second module's server with the iris dataset
  secondModuleServer(id = "dataDownload", dataset = iris)
  
  # Call the first module's server
  firstModuleServer(id = "firstModule")
  
}
ui.R
# Define the UI for the Shiny app
ui <- bs4DashPage(
  header = bs4DashNavbar(),
  sidebar = bs4DashSidebar(
    sidebarMenu(
      menuItem("First Module", tabName = "firstModule", icon = icon("home"))
    )
  ),
  controlbar = bs4DashControlbar(),
  footer = bs4DashFooter(),
  title = "Minimal Viable Shiny App",
  body = bs4DashBody(
    tabItems(
      tabItem(
        tabName = "firstModule",
        firstModuleUI(id = "firstModule", tabName = "firstModuleTab")
      )
    )
  )
)
first_module.R
#' A Shiny Module: Pass downloadable dataset to another module
#' @title Modularized Downloading
#' @description This module will pass iris to the other module where it should download

# Source the second module
source("modules/second_module.R", local = TRUE)

# Define the first module's UI
firstModuleUI <- function(id, tabName) {
  ns <- NS(id)
  tabItem(tabName = tabName,
          tabPanel("First Module",
                   box(title = "Reprex: Modularized Download",
                       dropdownMenu = secondModuleUI(id = ns("dataDownload"))
                   )
          )
  )
}

# Define the first module's server
firstModuleServer <- function(id) {
  moduleServer(id, function(input, output, session) {
    # Pass the iris dataset to the second module's server
    secondModuleServer(id = "dataDownload", dataset = iris)
  })
}
second_module.R
# A Shiny Module - To Download/Export Data In Different File Types
#' @title Download/Export User Updated Data
#' @description Users can download/export data as CSV


# Define the second module's UI
secondModuleUI <- function(id) {
  ns <- NS(id)
  boxDropdown(
    boxDropdownItem("CSV", id = ns("csvdownload"), icon = icon("file-csv")),
    icon = icon("download")
  )
}

secondModuleServer <- function(id, dataset) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns
    print(head(dataset)) # check if the data being received
    # Trigger the downloadHandler when the download_button is clicked
    observeEvent(input$csvdownload, {
      print("debug: button works")
      output$csvdownload <- downloadHandler(
        filename = function() {
          paste("iris.csv", sep = "")
        },
        content = function(file) {
          write.csv(dataset, file, row.names = FALSE)
          print("debug: download processed")
        }
      )
    })
    
  })
}

感谢您的帮助。

r shiny module shinyjs bs4dash
1个回答
0
投票

也许你正在寻找这个(其余代码没有变化)。

# Define the second module's UI
secondModuleUI <- function(id) {
  ns <- NS(id)
  boxDropdown(
    boxDropdownItem("", uiOutput(ns("csvdownload")) ),
    icon = icon("download")
  )
}

secondModuleServer <- function(id, dataset) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns
    print(head(dataset)) # check if the data being received
    # Trigger the downloadHandler when the download_button is clicked
    observeEvent(input$csvdownload, {
      print("debug: button works")
    })
    
    output$csvdownload <- renderUI({
      downloadBttn(ns("saveCSV"),
                   HTML("CSV"),
                   style = "fill",
                   color = "default",
                   size = "md",
                   block = TRUE,
                   no_outline = TRUE
      )
    })
    
    output$saveCSV <- downloadHandler(
      filename = function() {
        paste("iris.csv", sep = "")
      },
      content = function(file) {
        write.csv(dataset, file, row.names = FALSE)
        print("debug: download processed")
      }
    )
    
  })
}

# Define the UI for the Shiny app
ui <- bs4DashPage(
  header = bs4DashNavbar(),
  sidebar = bs4DashSidebar(
    sidebarMenu(
      menuItem("First Module", tabName = "firstModule", icon = icon("home"))
    )
  ),
  controlbar = bs4DashControlbar(),
  footer = bs4DashFooter(),
  title = "Minimal Viable Shiny App",
  body = bs4DashBody(
    tabItems(
      tabItem(
        tabName = "firstModule",
        firstModuleUI(id = "firstModule", tabName = "firstModuleTab")
      )
    )
  )
)

# Define the server for the Shiny app
## This isn't necessarily needed with the use of moduleServer()
## Included here in case the file is needed in the codebase
server <- function(input, output, session) {
  
  # Call the second module's server with the iris dataset
  #secondModuleServer(id = "dataDownload", dataset = iris)
  
  # Call the first module's server
  firstModuleServer(id = "firstModule")
  
}
© www.soinside.com 2019 - 2024. All rights reserved.