13
votes

I'm new to Shiny and struggling considerably.

I need to give my Shiny users the ability to download a data file (essentially querying a database). The query goes from one time to another. Shiny supports dates natively, but not time so I have to give the users a text field with a submitButton

The problem is I need to have the submit button do a validation test on both text inputs, and the either: 1) Return an error message if either input is not valid 2) Download the data, while giving status updates (data can take an hour easily--I do not want to leave users hanging).

I discovered something called renderPrint that seemed like a good option, in that it purports to output what has print to the console--then I can either print an error message or display the normal console output from the data download process. But then it holds the printed output until the whole process is done.

I'm thinking another possible solution would be to go back to renderText and then render text directly from the queryMagic function--as it goes through the data download process, it can periodically update output$text with new text. But I'm not sure how exactly to do this.

ui.R:

shinyUI(fluidPage(

  # Application title
  titlePanel("Demo Market Report"),

  fluidRow(

    column(4,
           h3("Extract Data"),
           helpText("Enter a start and end date/time of data to download. Be aware it takes about 10 minutes to download one hour of data.", strong("Date/time should be entered in yyyy-mm-dd hh:mm:ss format.")),
           textInput("fromDatetime", "From:", value = paste(with_tz(Sys.time(), "EST")-3600 )),
           textInput("toDatetime", "To:", value = paste(with_tz(Sys.time(), "EST"))),
           submitButton("Download Data Extract")
    ),
    column(4,
           textOutput("text1")
    )
  )


))

server.R:

shinyServer(
  function(input, output) {

    logText <- reactive({
      if (input$fromDatetime == "a") {
        data = queryMagic(blah,blah,blah) #this just gets the data, function is already used in production, I'll feed the shiny input into it but that seems straightforward
        return("victory")
      }
      else return("invalid")
    })

    output$text1 <- renderPrint({
      paste(logText())
    })


  }
)

Thanks in advance for help.

1

1 Answers

4
votes

I think capture.output is good solution for capturing text from console.

 server <- function(input, output) {
  values <- reactiveValues()

  queryMagic <- function() {
    print("Warning")

    return("Data")
  }
  output$console <- renderPrint({
    logText()
    return(print(values[["log"]]))
    # You could also use grep("Warning", values[["log"]]) to get warning messages and use shinyBS package
    # to create alert message
  })

  logText <- reactive({
    values[["log"]] <- capture.output(data <- queryMagic())


  })
}

ui <- shinyUI(fluidPage(
  sidebarLayout(
    sidebarPanel(
    ),
    mainPanel(verbatimTextOutput("console"))
  )
))

shinyApp(ui = ui, server = server)