web-dev-qa-db-fra.com

Bouton 'Réinitialiser les entrées' dans l'application brillante

Je voudrais implémenter un bouton 'Réinitialiser les entrées' dans mon application brillante. 

Voici un exemple avec seulement deux entrées où j'utilise les fonctions de mise à jour pour rétablir les valeurs par défaut:

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")
    })
  }

))

Ce que j'aimerais savoir, c'est s'il existe aussi une fonction qui remet tout en place par défaut? Cela serait utile en cas d'entrées multiples.

De plus, je ne suis pas sûr si mon utilisation de la fonction observer afin de détecter le moment où le bouton d'action a été touché est la "bonne façon" de gérer les boutons d'action? 

30
Insa

Il n’existe pas de telle fonction dans shiny, cependant, voici un moyen de le faire sans avoir à définir essentiellement vos entrées deux fois. L'astuce consiste à utiliser uiOutput et à encapsuler les entrées que vous souhaitez réinitialiser dans une div dont l'id devient quelque chose de nouveau chaque fois que vous appuyez sur le bouton de réinitialisation.

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"))
    })

  }
))
29
Matthew Plourde

Tout d’abord, votre utilisation de l’observateur est correcte, mais il existe un autre moyen légèrement plus agréable. Au lieu de 

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

Vous pouvez le changer pour

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

Notez également que vous n'avez pas besoin explicitement de "retourner" à partir d'une fonction renderText, la dernière instruction sera automatiquement utilisée. 


En ce qui concerne la question principale: la solution de Matthew est excellente, mais il existe également un moyen de réaliser ce que vous voulez sans avoir à déplacer toute votre interface utilisateur sur le serveur. Je pense qu'il est préférable de conserver votre interface utilisateur dans le fichier d'interface utilisateur simplement parce que la séparation de la structure et de la logique est généralement une bonne idée.

Clause de non-responsabilité: ma solution consiste à utiliser un package que j'ai écrit. Mon paquet shinyjs a une fonction reset qui vous permet de réinitialiser une entrée ou une section HTML à sa valeur d'origine. Voici comment modifier le code d'origine en fonction du comportement souhaité, de manière à ce qu'il s'adapte à un nombre quelconque d'entrées sans avoir à ajouter de code. Tout ce que je devais faire était d'ajouter un appel à useShinyjs() dans l'interface utilisateur, d'ajouter un attribut "id" au formulaire et d'appeler reset(id) sur le formulaire.

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")
    })
  }

))
25
DeanAttali

Voici une autre option qui fonctionne pour les entrées statiques ou dynamiques et n'implique pas une nouvelle restitution du rendu des entrées.

Il utilise:

reactiveValuesToList pour obtenir toutes les valeurs d'entrée initiales et (éventuellement) les valeurs d'entrée dynamiques initialisées par la suite.

session$sendInputMessage pour mettre à jour les valeurs des entrées génériques. Les fonctions updateXyzInput appellent cela sous le capot comme suit: session$sendInputMessage(inputId, list(value = x, ...)

Chaque entrée Shiny utilise value pour son message d’entrée et presque toutes seront mises à jour avec leur valeur d’entrée telle quelle. Seules deux entrées que j'ai trouvées nécessitent un boîtier spécial: checkboxGroupInput pour ne pas envoyer NULL lorsque rien n'est coché, et dateRangeInput pour convertir sa c(start, end) en list(start = start, end = end).

Ce n'est peut-être pas une bonne idée de réinitialiser aveuglément TOUTES les entrées (même les onglets seront réinitialisés), mais cela peut facilement être adapté pour réinitialiser un ensemble filtré d'entrées.

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)
1
greg L

Vous pouvez également créer un bouton de réinitialisation en affectant NULL à votre objet de valeurs réactives. 

Voir cet article RStudio Shiny sur Utilisation des boutons d'action: http://shiny.rstudio.com/articles/action-buttons.html . Lisez plus précisément les sections intitulées motif 4 - boutons de réinitialisation} et motif 5 - réinitialisation lors du changement de tabulation. Des exemples (y compris le code) sont fournis dans l'article.

L'article propose des solutions qui ne nécessitent pas de packages supplémentaires si cela pose un problème.

1
jordan