Shiny Dashboard - display a dedicated “loading..”

2019-01-15 07:09发布

I have initial loading of data from the DB in the server.R which takes a few seconds. Until this is done, the page displayed is distorted (wrong data in selection box, and weird placing of the boxes, see below). Distorted display

I want to display a different page (or at least different content in my first-displayed tab) until the data is completely loaded.

I thought about doing some kind of conditionalPanel using a condition based on a dedicated global variable (initial_loading_done), but wherever I tried placing the conditionalPanel it didn't work.

This is the structure of my UI.R:

shinyUI(

  dashboardPage(
    dashboardHeader(title = "Title"),
    dashboardSidebar(
       sidebarMenu(
           menuItem("Tab1", tabName = "Tab1",icon = icon("dashboard")),
           menuItem("Tab2", tabName = "Tab2",  icon = icon("bar-chart-o"))
       )
    ),
    dashboardBody(
       includeCSS("custom_css.css"),
       tabItems(
           tabItem(tabName = "Tab1", 
                   fluidRow(<content>),
                   mainPanel(
                      fluidRow(<content>)
                   )
           ),
           tabItem(tabName = "Tab2",
                  fluidRow(<content>),
                  mainPanel(
                      dataTableOutput('my_data_table')  
                  )
           )
       )
    )
 )
)

3条回答
不美不萌又怎样
2楼-- · 2019-01-15 08:00

In server I like to use reactiveValues() to store a setupComplete condition. Then, when the data is loaded my setupComplete is set to TRUE.

In the ui we can then assess this setupComplete condition in a conditionalPanel, and only display the content (in my example the three box() widgets).

Here's a working example

## app.R ##
library(shiny)
library(shinydashboard)
library(shinyjs)

ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
        actionButton(inputId = "btn_data", label = "Download"),
        conditionalPanel(condition = "output.setupComplete",
            box( title = "box1" ),
            box( title = "box2" ),
            box( title = "boc3" )
        ),
        conditionalPanel(condition = "!output.setupComplete",
                         box( title = "loading"))
    )
)

server <- function(input, output) { 

    rv <- reactiveValues()
    rv$setupComplete <- FALSE

    ## simulate data load
    observe({

        if(input$btn_data){

            df <- data.frame(id = seq(1,200),
                             val = rnorm(200, 0, 1))

            ## Simulate the data load
            Sys.sleep(5)
            ## set my condition to TRUE
            rv$setupComplete <- TRUE
        }

        ## the conditional panel reads this output
        output$setupComplete <- reactive({
            return(rv$setupComplete)
        })
        outputOptions(output, 'setupComplete', suspendWhenHidden=FALSE)

    })
}

shinyApp(ui, server)
查看更多
三岁会撩人
3楼-- · 2019-01-15 08:05

Here's a very simple example using shinyjs package

The idea is to create the loading "page" and the content "page" under different IDs, have the content page initially hidden, and use show() and hide() after the app is ready

library(shiny)
library(shinyjs)

load_data <- function() {
  Sys.sleep(2)
  hide("loading_page")
  show("main_content")
}

ui <- fluidPage(
  useShinyjs(),
  div(
    id = "loading_page",
    h1("Loading...")
  ),
  hidden(
    div(
      id = "main_content",
      "Data loaded, content goes here"
    )
  )
)

server <- function(input, output, session) {
  load_data()
}

shinyApp(ui = ui, server = server)
查看更多
Rolldiameter
4楼-- · 2019-01-15 08:13

The code

hidden(
    div(
      id = "main_content",
      "Data loaded, content goes here"
    )

doesn't work with tabsetPanel. But if you move the id to the div level it works beautifully. Thanks to shinyjs author Dean Attali for this tip. https://stackoverflow.com/users/4432127/keshete

  hidden(
        div(id = "mainTabsetPanel",
          tabsetPanel(
....
查看更多
登录 后发表回答