Author: Julien Barnier
Date: 2023-02-15

# Conditional controls and screen output

#### Julien Barnier

#### 2023-02-15

## Conditional controls

Sometimes you don’t want your user to be able to go to the next screen if a condition based on inputs is not met. This can be done in `shinyglide` with the `next_condition` argument of the `screen` function. This option takes exactly the same syntax has the one used in `shiny::conditionalPanel`.

For example, in the following app, the Next button is disabled until the n value is greater then zero :

    ui <- fluidPage(
      glide(
        screen(
          next_condition = "input.n > 0",

          p("Please choose a value for n :"),
          numericInput("n", "n :", value = 0)
        ),
        screen(
          p("Here is your plot :"),
          plotOutput("plot")
        )
      )
    )

    server <- function(input, output, session) {
      output$plot <- renderPlot({
        hist(rnorm(input$n), main = paste("n =", input$n))
      })
    }

    shinyApp(ui, server)

You can do the same for the Back button with the `previous_condition` argument.

By default the button is disabled when the condition is not met (more precisely, the button gets a `disabled = "disabled"` argument and a `disabled` CSS class). If you prefer to hide it entirely, you can add `disable_type = "hide"` to your `glide()` definition :

    ui <- fluidPage(
      glide(
        disable_type = "hide",

        screen(
          next_condition = "input.n > 0",

          p("Please choose a value for n :"),
          numericInput("n", "n :", value = 0)
        ),
        screen(
          p("Here is your plot :"),
          plotOutput("plot")
        )
      )
    )

    server <- function(input, output, session) {
      output$plot <- renderPlot({
        hist(rnorm(input$n), main = paste("n =", input$n))
      })
    }

    shinyApp(ui, server)

## Screen output

Sometimes you want to show a screen only if certain conditions are met based on inputs. For example, if a user chooses a value which is not present in a dataset, you would like to display a specific screen to alert him.

This is possible by using a `screenOutput` call in you app UI, associated to a `renderUI` in your app server. If `renderUI` returns `NULL`, the screen will be hidden.

Here is an example :

    ui <- fluidPage(
      glide(
        disable_type = "hide",

        screen(
          p("Do you want to see the next screen ?"),
          checkboxInput("check", "Yes, of course !", value = FALSE)
        ),
        screenOutput("check_screen"),
        screen(
          p("And this is the last screen")
        )
      )
    )

    server <- function(input, output, session) {
      output$check_screen <- renderUI({
        if(!input$check) return(NULL)
        p("Here it is !")
      })
      outputOptions(output, "check_screen", suspendWhenHidden = FALSE)
    }

    shinyApp(ui, server)

Important : for the `screenOutput` to work, it is mandatory to add the following line in your app server :

    outputOptions(output, "your_screen_id", suspendWhenHidden = FALSE)

Otherwise, it won’t be updated when hidden.

Sometimes the `screenOutput` computation takes some time. In these cases, with the default controls, the Next button is disabled and a Loading message is shown until the next screens computations is done. You can see it in the following example, which is the same as the previous one but with an articial 2 seconds waiting time :

    ui <- fluidPage(
      glide(
        disable_type = "hide",

        screen(
          p("Do you want to see the next screen ?"),
          checkboxInput("check", "Yes, of course !", value = FALSE)
        ),
        screenOutput("check_screen"),
        screen(
          p("And this is the last screen")
        )
      )
    )

    server <- function(input, output, session) {
      output$check_screen <- renderUI({
        Sys.sleep(2)
        if(!input$check) return(NULL)
        p("Here it is !")
      })
      outputOptions(output, "check_screen", suspendWhenHidden = FALSE)
    }

    shinyApp(ui, server)

### Customizing loading

You can customize the loading label and animation with options passed to `glide()` :

- `loading_class` (default value : `"loading"`) : a CSS class passed to the Next button when in loading state
- `loading_label` : the label of the Next button while in loading state. This can be any HTML, and you can insert a `span(class = "shinyglide-spinner")` in it if you want to display the defautl animated spinner somewhere.

You can take a look at the custom controls sample app for an example of loading customization with custom controls and CSS.