47

I would like to implement a 'Reset inputs' button in my shiny app.

Here is an example with just two inputs where I'm using the update functions to set the values back to the default values:

library(shiny)

runApp(list(

  ui = pageWithSidebar(

    headerPanel("'Reset inputs' button example"),

    sidebarPanel(
      numericInput("mynumber", "Enter a number", 20),
      textInput("mytext", "Enter a text", "test"),
      tags$hr(),
      actionButton("reset_input", "Reset inputs")
    ),

    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary")
    )

  ),

  server = function(input, output, session) {

    output$summary <- renderText({
      return(paste(input$mytext, input$mynumber))
    })

    observe({
      input$reset_input
      updateNumericInput(session, "mynumber", value = 20)
      updateTextInput(session, "mytext", value = "test")
    })
  }

))

What I would like to know is if there is also a function that sets back everything to default? That would be useful in case of multiple inputs.

Additionally, I'm not sure if my use of the observe function in order to detect when the action button was hit is the 'proper way' of handling the action buttons?

Insa
  • 688
  • 1
  • 7
  • 9

4 Answers4

50

First of all, your use of the observer is correct, but there is another way that's slightly nicer. Instead of

observe({
  input$reset_input
  updateNumericInput(session, "mynumber", value = 20)
  updateTextInput(session, "mytext", value = "test")
})

You can change it to

observeEvent(input$reset_input, {
  updateNumericInput(session, "mynumber", value = 20)
  updateTextInput(session, "mytext", value = "test")
})

Also note that you don't need to explicitly "return" from a renderText function, the last statement will automatically be used.


Regarding the main question: Matthew's solution is great, but there's also a way to achieve what you want without having to move all your UI into the server. I think it's better practice to keep your UI in the UI file just because separation of structure and logic is generally a good idea.

Full disclaimer: my solution involves using a package that I wrote. My package shinyjs has a reset function that allows you to reset an input or an HTML section back to its original value. Here is how to tweak your original code to your desired behaviour in a way that will scale to any number of inputs without having to add any code. All I had to do is add a call to useShinyjs() in the UI, add an "id" attribute to the form, and call reset(id) on the form.

library(shiny)

runApp(list(

  ui = pageWithSidebar(

    headerPanel("'Reset inputs' button example"),

    sidebarPanel(
      shinyjs::useShinyjs(),
      id = "side-panel",
      numericInput("mynumber", "Enter a number", 20),
      textInput("mytext", "Enter a text", "test"),
      tags$hr(),
      actionButton("reset_input", "Reset inputs")
    ),

    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary")
    )

  ),

  server = function(input, output, session) {

    output$summary <- renderText({
      return(paste(input$mytext, input$mynumber))
    })

    observeEvent(input$reset_input, {
      shinyjs::reset("side-panel")
    })
  }

))
DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • I was looking for some help on filtering data and generating crosstables and plots. I would really appreciate any help in let me know how to get this working. I have posted my question and hoping you would be able to suggest some solution. Thank you!! Link to my post is http://stackoverflow.com/questions/41187194/shiny-dynamic-filter-variable-selection-and-display-of-variable-values-for-selec – user1412 Jan 07 '17 at 15:13
  • Thank you Dean, do you think it's possible to add yours function directly in shiny or shinydashboards packages ? – Mostafa90 Mar 01 '17 at 15:08
  • 2
    @DimitriPetrenko do you mean moving the reset function into shiny? I don't think that's going to happen. You can ask rstudio about it, if they want to. But shinyjs has lots of other similarly useful functions so I think it makes sense to keep them packages together – DeanAttali Mar 01 '17 at 22:34
  • 1
    @DeanAttali If you're using `flexdashboard` what argument do your refer to within `shinyjs::reset()` to indicate you want to reset the sidebar panel? The issue is that in `flexdashboard` you don't explicitly provide an `id` name to the sidebar panel. – Phil Jun 08 '17 at 19:46
  • 1
    Never mind - I realize you can refer to the inputs themselves, which works just as well. – Phil Jun 08 '17 at 20:10
41

There isn't such a function in shiny, however, here's a way to accomplish this without having to essentially define your inputs twice. The trick is to use uiOutput and wrap the inputs you want to reset in a div whose id changes to something new each time the reset button is pressed.

library(shiny)

runApp(list(

  ui = pageWithSidebar(

    headerPanel("'Reset inputs' button example"),

    sidebarPanel(
      uiOutput('resetable_input'),
      tags$hr(),
      actionButton("reset_input", "Reset inputs")
    ),

    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary")
    )

  ),

  server = function(input, output, session) {

    output$summary <- renderText({
      return(paste(input$mytext, input$mynumber))
    })

    output$resetable_input <- renderUI({
        times <- input$reset_input
        div(id=letters[(times %% length(letters)) + 1],
            numericInput("mynumber", "Enter a number", 20),
            textInput("mytext", "Enter a text", "test"))
    })

  }
))
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
  • Many thanks! I have tried the code already on my original app (with 11 instead of 2 inputs) and it works really fine and it is a good thing not to have the inputs twice in the code. Btw: Do I find somewhere a good help for the html tags? I wasn't aware of the "id" and its usefulness so far. – Insa Jun 18 '14 at 07:23
  • 3
    @Matthew Plourde, @Insa I don't think div and id are really important here. I replaced `div(id=letters[(times %% length(letters)) + 1],` by `list` and it changed nothing. – Marat Talipov Jan 03 '15 at 01:54
  • 1
    this is one of those answers I find myself back at again, and wish I could upvote, but must have done so in the distant past. So much simpler than writing an observer and having to rewrite everything. – Rorschach Oct 12 '15 at 19:44
  • Gotta say, this was a HUGE time saver...if only I saw it before I wasted my time! – robin.datadrivers Apr 27 '16 at 04:11
  • Just stumbled across this solution before I even knew exactly what I was trying to search for (updateTextInput?). Fantastic solution. – Adrian Jun 24 '16 at 09:28
  • @MatthewPlourde, I was looking for some help on filtering data and generating crosstables and plots. I would really appreciate any help in let me know how to get this working. I have posted my question and hoping you would be able to suggest some solution. Thank you!! Link to my post is http://stackoverflow.com/questions/41187194/shiny-dynamic-filter-variable-selection-and-display-of-variable-values-for-selec – user1412 Jan 07 '17 at 15:15
  • Great idea indeed! Thanks a million – Arthur Apr 19 '17 at 13:22
  • I saw this as an answer first, but still have a question: does not it generate a new div() with as many inputs each time it is reset? in terms of memory, I don't think it is the best. – Elie Ker Arno Oct 03 '19 at 14:20
  • I believe this answer is outdated. There is a reset() function currently https://www.rdocumentation.org/packages/shinyjs/versions/1.1/topics/reset – Michael Apr 07 '20 at 00:46
9

Here is yet another option that works for either static or dynamic inputs, and doesn't involve re-rendering inputs entirely.

It uses:

reactiveValuesToList to get all initial input values, and (optionally) any dynamic input values that get initialized afterward.

session$sendInputMessage to update values for generic inputs. The updateXyzInput functions call this under the hood like session$sendInputMessage(inputId, list(value = x, ...).

Every Shiny input uses value for its input message, and almost all will update with their input value as-is. Only a two inputs I've found need special casing - checkboxGroupInput to not send NULL when nothing is checked, and dateRangeInput to convert its c(start, end) to a list(start = start, end = end).

It may not be a good idea to blindly reset ALL inputs (even tabs will be reset), but this can easily be adapted to reset a filtered set of inputs.

library(shiny)

ui <- pageWithSidebar(
  headerPanel("'Reset inputs' button example"),

  sidebarPanel(
    numericInput("mynumber", "Enter a number", 20),
    textInput("mytext", "Enter text", "test"),
    textAreaInput("mytextarea", "Enter text", "test"),
    passwordInput("mypassword", "Enter a password", "password"),
    checkboxInput("mycheckbox", "Check"),
    checkboxGroupInput("mycheckboxgroup", "Choose a number", choices = c(1, 2, 3)),
    radioButtons("myradio", "Select a number", c(1, 2, 3)),
    sliderInput("myslider", "Select a number", 1, 5, c(1,2)),
    uiOutput("myselUI"),
    uiOutput("mydateUI"),
    tags$hr(),
    actionButton("reset_input", "Reset inputs")
  ),

  mainPanel(
    h4("Summary"),
    verbatimTextOutput("summary")
  )
)

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

  initialInputs <- isolate(reactiveValuesToList(input))

  observe({
    # OPTIONAL - save initial values of dynamic inputs
    inputValues <- reactiveValuesToList(input)
    initialInputs <<- utils::modifyList(inputValues, initialInputs)
  })

  observeEvent(input$reset_input, {
    for (id in names(initialInputs)) {
      value <- initialInputs[[id]]
      # For empty checkboxGroupInputs
      if (is.null(value)) value <- ""
      session$sendInputMessage(id, list(value = value))
    }
  })

  output$myselUI <- renderUI({
    selectInput("mysel", "Select a number", c(1, 2, 3))
  })

  output$mydateUI <- renderUI({
    dateInput("mydate", "Enter a date")
  })

  output$summary <- renderText({
    return(paste(input$mytext, input$mynumber))
  })
}

shinyApp(ui, server)
greg L
  • 4,034
  • 1
  • 19
  • 18
3

You can also create a reset button by assigning NULL to your reactive values object.

See this RStudio Shiny article on Using Action Buttons: http://shiny.rstudio.com/articles/action-buttons.html. Specifically, read the sections titled Pattern 4 - Reset buttons and Pattern 5 - Reset on tab change. Examples (including code) are provided in the article.

The article provides solutions that don't require additional packages if that's a concern.

jordan
  • 388
  • 3
  • 14