Kasia Kulma
Kasia Kulma

Reputation: 1722

shiny: apply shinycustomerloader after pressing actionButton

BACKGROUND

I have an app where a user chooses a file name from a drop-down menu (selectizeInput) and confirms the choice with an actionButton. The app will display the results in the DT::dataTableOutput format.

OBJECTIVE

I'd like to be able to show a loading screen (using shinydashboardloader package) but only AFTER a user presses the actionButton. Prior that I'd like to show an empty screen. Additionally, if a user wants to try several files in one session, the loading screen should appear every time the actionButton has been pressed and disappear when the dataset has been loaded.

CURRENT STATE

Currently, if I run this app the loading button appears all the time, also before a user makes a file choice

### ui.R
library(shiny)
library(shinydashboard)
library(DT)
library(shinycustomloader)

dashboardPage(
  dashboardHeader(),
  dashboardSidebar(

selectizeInput("file", "Select File",
               c("fileA", "fileB")), 

actionButton("submit", "Submit")
  ),
  dashboardBody(
    fluidRow(
      box(h2("My Data"),
      div(style = 'overflow-x: scroll', 
          withLoader(DT::dataTableOutput('mytable'),
                     type = "html",
                     loader = "loader1")),
      width = 12)

  )
  )
)


#### server.R
library(shiny)
library(shinydashboard)
library(DT)


shinyServer(function(input, output, session) {  

  file_name <- reactive({ 
req(input$file)
  })


  # When the Submit button is clicked, start the cleaning and matching 
  observeEvent(input$submit, {

## open chosen file 
#    open_file <- read_excel(paste0("input_files/", file_name()))

### + some processing that gives me matched_df

matched_df <- data.frame(A = c(1, 2, 3, 4),
                         B = c("A", "B", "C", "D"))

selected <- reactive({

  matched_df # + apply some filter

}) 



output$mytable = DT::renderDataTable({
  selected()
})


  })

})

I'm guessing that the way forward would be to use conditionalPanel but I'm not sure how to make a click on the actionButton a condition.

UPDATE

I applied conditionalPanel to the datatable, but it works only the first time I press "Submit" button. If in the same session I change the file name and press the button again, the loader won't appear. Any ideas how I can make it work multiple times in one session?

  dashboardBody(
     fluidRow(
      box(h2("My Data"),
          conditionalPanel("input.submit==1",
          div(style = 'overflow-x: scroll', 
              withLoader(DT::dataTableOutput('mytable'),
                     type = "html",
                     loader = "loader1"))
      ),
      width = 12)

Any help will be great, thanks!

Upvotes: 3

Views: 2656

Answers (1)

divibisan
divibisan

Reputation: 12155

1: I'm not familiar with shinydashboardloader but I was able add a loading indicator to my app by using the shinyjs package to hide and show elements using CSS. I would add your loading page elements to your main page and wrap them in a shinyjs::hidden function so they're hidden by default. Then when the user clicks the action button, call shinyjs::showElement to show them and shinyjs::hideElement to hide them once loading is complete.

UI:

shinyjs::hidden(div(id = 'loading',
           # PUT LOADING ELEMENTS HERE))

SERVER:

observeEvent(input$submit, {
    # Show element once submit button is pressed
    shinyjs::showElement(id = 'loading')

    # CODE TO MAKE DATA FRAME

    # Hide loading element when done
    shinyjs::hideElement(id = 'loading')
)

2: As for your problem with your edit, the reason that your conditional panel only shows the first time is that the value of an actionButton increases by one each time it is clicked. So the first time it is clicked it goes from 0 to 1; if you click it again it goes from 1 to 2 and so on. Since you set the condition to input$select == 1, it will only appear if the button has been clicked exactly 1 time.

To get it to do what you want, you either need to change the condition to input$select > 1 so that it appears as long as the button has been clicked once, or add a reactiveValue that gets set to 1 when the button is clicked and then resets to 0 when another condition is met (like when loading finishes).

rv <- reactiveValues(loading = 0)

# When you click submit, show the loading screen
observeEvent(input$submit, {rv$loading <- 1})

# When you click LOAD, start loading, then hide the loading screen when finished
observeEvent(input$LOAD, {

    # CODE TO LOAD AND GENERATE DATA HERE

    rv$loading <- 0})

Upvotes: 3

Related Questions