Reputation: 141
I define a module to import excel. Hoping we can return the data and the name of excel to a global rv.
I observe the read event in console, I put a verbatimTextOutput() in UI, but the passing failed, print() always NULL, the value didn't return to the vectors I want.
Any advice would be greatly appreciated.
excelInput <- function(id) {
ns <- NS(id)
tagList(
div(style = "margin-bottom: -15px;", fileInput(ns("excel"), label = ".csv, or .xlsx", accept = c(".csv", ".xlsx"), multiple = FALSE)),
uiOutput(ns("sheetUI")),
uiOutput(ns("readUI"))
)
}
excelInputServer <- function(id, needRead, data_rv, name_rv = NULL) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
ext <- reactive({tools::file_ext(input$excel$name)})
output$sheetUI <- renderUI({
req(ext())
if (ext() == "xlsx") {
selectInput(ns("sheet"), "Sheet", choices = readxl::excel_sheets(input$excel$datapath))
}
})
if (needRead == TRUE) {
output$readUI <- renderUI({
actionButton(ns("read"), "Read")
})
observe({
shinyjs::toggleState("read", condition = !is.null(input$excel))
})
observeEvent(input$read, {
if (ext() == "csv") {
data_rv <- readr::read_csv(input$excel$datapath)
if (!is.null(name_rv)) {
name_rv <- stringr::str_extract(input$excel$name, ".*(?=\\.)")
}
} else if (ext() == "xlsx") {
data_rv <- readxl::read_xlsx(input$excel$datapath, input$sheet)
if (!is.null(name_rv)) {
name_rv <- paste0(stringr::str_extract(input$excel$name, ".*(?=\\.)"), "_#", input$sheet, "#")
}
}
})
} else {
observe({
req(ext())
if (ext() == "csv") {
data_rv <- readr::read_csv(input$excel$datapath)
if (!is.null(name_rv)) {
name_rv <- stringr::str_extract(input$excel$name, ".*(?=\\.)")
}
} else if (ext() == "xlsx") {
data_rv <- readxl::read_xlsx(input$excel$datapath, input$sheet)
if (!is.null(name_rv)) {
name_rv <- paste0(stringr::str_extract(input$excel$name, ".*(?=\\.)"), "_#", input$sheet, "#")
}
}
})
}
})
}
library(shiny)
shinyApp(
ui <- fluidPage(
shinyjs::useShinyjs(),
fluidRow(
column(width = 4, excelInput("needRead")),
column(width = 8, verbatimTextOutput("print1"))
),
fluidRow(
column(width = 4, excelInput("noRead")),
column(width = 8, verbatimTextOutput("print2"))
)
),
server <- function(input, output, session) {
rv <- reactiveValues()
excelInputServer("needRead", TRUE, rv$data_test1, rv$filename_test1)
output$print1 <- renderPrint({
print(rv$filename_test1)
print(rv$data_test1)
})
excelInputServer("noRead", FALSE, rv$data_test1)
output$print2 <- renderPrint({
print(rv$filename_test2)
print(rv$data_test2)
})
}
)
Upvotes: 0
Views: 76
Reputation: 84529
I think you want something like that. You have to return some objects from the server module.
library(shiny)
excelInput <- function(id) {
ns <- NS(id)
tagList(
div(style = "margin-bottom: -15px;", fileInput(ns("excel"), label = ".csv, or .xlsx", accept = c(".csv", ".xlsx"), multiple = FALSE)),
uiOutput(ns("sheetUI")),
uiOutput(ns("readUI"))
)
}
excelInputServer <- function(id, needRead) {
moduleServer(
id,
function(input, output, session) {
ns <- session$ns
ext <- eventReactive(
input$excel, {
tools::file_ext(input$excel$name)
})
output$sheetUI <- renderUI({
req(ext())
if (ext() == "xlsx") {
selectInput(ns("sheet"), "Sheet", choices = readxl::excel_sheets(input$excel$datapath))
}
})
Data <- reactiveVal()
Name <- reactiveVal()
if(needRead) {
output$readUI <- renderUI({
actionButton(ns("read"), "Read")
})
observe({
shinyjs::toggleState("read", condition = !is.null(input$excel))
})
observeEvent(input$read, {
if (ext() == "csv") {
dat <- readr::read_csv(input$excel$datapath)
Data(dat)
Name(stringr::str_extract(input$excel$name, ".*(?=\\.)"))
} else if (ext() == "xlsx") {
dat <- readxl::read_xlsx(input$excel$datapath, input$sheet)
Data(dat)
Name(paste0(stringr::str_extract(input$excel$name, ".*(?=\\.)"), "_#", input$sheet, "#"))
}
})
} else {
observe({
req(ext())
if (ext() == "csv") {
dat <- readr::read_csv(input$excel$datapath)
Data(dat)
Name(stringr::str_extract(input$excel$name, ".*(?=\\.)"))
} else if (ext() == "xlsx") {
dat <- readxl::read_xlsx(input$excel$datapath, input$sheet)
Data(dat)
Name(paste0(stringr::str_extract(input$excel$name, ".*(?=\\.)"), "_#", input$sheet, "#"))
}
})
}
return(list(data = Data, name = Name))
}
)
}
library(shiny)
shinyApp(
ui <- fluidPage(
shinyjs::useShinyjs(),
fluidRow(
column(width = 4, excelInput("needRead")),
column(width = 8, verbatimTextOutput("print1"))
),
fluidRow(
column(width = 4, excelInput("noRead")),
column(width = 8, verbatimTextOutput("print2"))
)
),
server <- function(input, output, session) {
x1 <- excelInputServer("needRead", TRUE)
output$print1 <- renderPrint({
print(x1$data())
print(x1$name())
})
x2 <- excelInputServer("noRead", FALSE)
output$print2 <- renderPrint({
print(x2$data())
print(x2$name())
})
}
)
Upvotes: 1
Reputation: 21297
Delay the reactive fraction of a second, and it works fine. Try this
library(readxl)
excelInput <- function(id) {
ns <- NS(id)
tagList(
div(style = "margin-bottom: -15px;",
fileInput(ns("excel"), label = ".csv, or .xlsx", accept = c(".csv", ".xlsx"), multiple = FALSE) ),
shinyjs::hidden(selectInput(ns("sheet"), "Sheet", choices = c(Choose = "")))
)
}
excelInputServer <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
ext <- tools::file_ext(input$excel$name)
observeEvent(input$excel, {
req(ext)
if (stringr::str_ends(input$excel$datapath, "(xlsx|xls)") ) {
shinyjs::show("sheet")
inFile <- input$excel
sheetnames <- excel_sheets(path = inFile$datapath)
updateSelectInput(session, "sheet", choices = sheetnames)
}else if (stringr::str_ends(input$excel$datapath, "csv")){ ### set sheets to NULL if csv is selected
updateSelectInput(session, "sheet", choices = character(0))
shinyjs::hide("sheet")
}
}, ignoreNULL = TRUE, ignoreInit = TRUE)
myreturn <- reactive({
req(ext,input$excel)
Sys.sleep(0.3)
if (ext == "csv") {
file = str_extract(input$excel$name, ".*(?=\\.)")
dt = read.csv2(input$excel$datapath)
} else if (ext == "xlsx") {
req(input$sheet)
file = paste0(str_extract(input$excel$name, ".*(?=\\.)"), "_#", input$sheet, "#")
dt = readxl::read_xlsx(input$excel$datapath, input$sheet)
}
return(list(
filename = file,
data = dt
))
})
return(myreturn)
})
}
shinyApp(
ui <- fluidPage(
shinyjs::useShinyjs(),
fluidRow(
column(width = 4, excelInput("test")),
column(width = 8, verbatimTextOutput("print"))
)
),
server <- function(input, output, session) {
rv <- reactiveValues()
observe({
extract <- excelInputServer("test")
rv$filename_test <- extract()[[1]]
rv$data_test <- extract()[[2]]
})
output$print <- renderPrint({
print(rv$filename_test)
print(rv$data_test)
})
}
)
Upvotes: 0