Author: Andy Merlino
Date: 2021-09-23

# shinyFeedback Introduction

#### Andy Merlino

#### 2021-09-23

## Functionality

The `shinyFeedback` package displays user friendly messages that appear alongside `shiny` inputs. e.g.

`shinyFeedback` currently works with the following `shiny` and `shinyWidgets` inputs:

- `shiny::dateInput()`
- `shiny::dateRangeInput()`
- `shiny::fileInput()`
- `shiny::numericInput()`
- `shiny::passwordInput()`
- `shiny::selectInput()`
- `shiny::sliderInput()`
- `shiny::textAreaInput()`
- `shiny::textInput()`
- `shinyWidgets::airDatepickerInput()`
- `shinyWidgets::pickerInput()`

## Setup

In order to use `shinyFeedback` you need to include the `useShinyFeedback()` function at the top of your UI.

The following is a minimal example of a `shiny` app that uses `shinyFeedback`. Run the following code in your R console to run the app.

    library(shiny)
    library(shinyFeedback)

    ui <- fluidPage(
      useShinyFeedback(), # include shinyFeedback

      textInput(
        "myInput",
        "Warn if >3 characters",
        value = ""
      )
    )

    server <- function(input, output, session) {
      observeEvent(input$myInput, {

        if (nchar(input$myInput) > 3) {
          showFeedbackWarning(
            inputId = "myInput",
            text = "too many chars"
          )
        } else {
          hideFeedback("myInput")
        }

      })
    }

    shinyApp(ui, server)

The above app has one `textInput()` input in the UI. In the server function, we write the code to conditionally display a feedback message. If the text input has more than 3 characters, the feedback message is displayed.

# `feedback()`

The `feedback()` function is an alternative to using `showFeedback()` and `hideFeedback()`. With `feedback()` the feedback message is shown/hidden based on whether the `show` argument to `feedback()` is “truthy”. “truthiness” is determined by `shiny::isTruthy()`. `feedback()` works nicely with reactive expressions that use `shiny::req()` to check the validity of Shiny inputs. e.g.

    library(shiny)
    library(shinyFeedback)

    ui <- fluidPage(
      useShinyFeedback(), # include shinyFeedback

      selectInput(
        "dataset",
        "Dataset",
        choices = c(
          "airquality",
          "Unknown dataset"
        )
      ),

      tableOutput('data_table')
    )

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

      data_out <- reactive({
        req(input$dataset)

        dataset_exists <- exists(input$dataset, "package:datasets")
        feedbackWarning("dataset", !dataset_exists, "Unknown dataset")
        req(dataset_exists, cancelOutput = TRUE)

        get(input$dataset, "package:datasets")
      })

      output$data_table <- renderTable({
        head(data_out())
      })
    }

    shinyApp(ui, server)

## Usage Inside Shiny Modules

`shinyFeedback` works inside shiny modules.

As for all modules, input and output IDs in the module UI code must be wrapped in `shiny::ns()` calls. Inside your module server code, you need not wrap input or output IDs inside `shiny::ns()`; shinyFeedback will automatically prepend the namespace of your current module.

Here is a simple example using shinyFeedback inside a module:

    library(shiny)
    library(shinyFeedback)

    numberInput <- function(id) {
      ns <- NS(id)
      tagList(
        useShinyFeedback(),
        numericInput(
          ns("warningInput"),
          "Warn if Negative",
          value = 0
        )
      )
    }

    number <- function(input, output, session) {
      observeEvent(input$warningInput, {
        req(input$warningInput)
        if (input$warningInput < 0) {
          showFeedbackWarning(inputId = "warningInput")
        } else {
          hideFeedback("warningInput")
        }
      })
    }

    ui <- fluidPage(
      numberInput(id = "numberFoo")
    )

    server <- function(input, output) {
      callModule(module = number, id = "numberFoo")
    }

    shinyApp(ui, server)