2014-06-17 2 views
24

Vorrei implementare un pulsante "Ripristina input" nella mia app lucida.Pulsante "Ripristina input" nell'app lucida

Ecco un esempio con due soli ingressi dove sto utilizzando le funzioni di aggiornamento per impostare i valori di nuovo ai valori di default:

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

)) 

Quello che vorrei sapere è se c'è anche una funzione che riporta tutto al valore predefinito? Ciò sarebbe utile in caso di più input.

Inoltre, non sono sicuro se il mio uso della funzione di osservazione per rilevare quando è stato premuto il pulsante di azione è il "modo corretto" di gestire i pulsanti di azione?

risposta

23

Non esiste una tale funzione in shiny, tuttavia, ecco un modo per ottenere ciò senza dover essenzialmente definire i propri input due volte. Il trucco è utilizzare uiOutput e inserire gli input che si desidera ripristinare in un div il cui ID cambia in qualcosa di nuovo ogni volta che si preme il pulsante di ripristino.

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

    } 
)) 
+0

Bella idea ..... – jdharrison

+0

Molte grazie! Ho provato il codice già sulla mia app originale (con 11 invece di 2 ingressi) e funziona davvero bene ed è una buona cosa non avere gli ingressi due volte nel codice. Btw: Trovo da qualche parte un buon aiuto per i tag html? Non ero a conoscenza dell '"id" e della sua utilità fino ad ora. – Insa

+1

@Matthew Plourde, @Insa Non credo che div e id siano davvero importanti qui. Ho sostituito 'div (id = letters [(volte %% length (letters)) + 1],' by 'list' e non ha cambiato nulla –

21

Prima di tutto, l'utilizzo dell'osservatore è corretto, ma c'è un altro modo leggermente più bello. Invece di

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

Si può cambiare a

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

Si noti inoltre che non è necessario in modo esplicito "ritorno" da una funzione renderText, verrà automaticamente utilizzato l'ultima istruzione.


Per quanto riguarda la questione principale: la soluzione di Matteo è grande, ma c'è anche un modo per ottenere ciò che si vuole, senza dover spostare tutta l'interfaccia utente al server. Penso che sia meglio mantenere l'interfaccia utente nel file dell'interfaccia utente solo perché la separazione della struttura e della logica è generalmente una buona idea.

Disclaimer completo: la mia soluzione prevede l'utilizzo di un pacchetto che ho scritto. Il pacchetto shinyjs ha una funzione reset che consente di ripristinare un input o una sezione HTML al suo valore originale. Ecco come modificare il codice originale per il comportamento desiderato in un modo che si ridurrà a un numero qualsiasi di input senza dover aggiungere alcun codice. Tutto quello che dovevo fare è aggiungere una chiamata a useShinyjs() nell'interfaccia utente, aggiungere un attributo "id" al modulo e chiamare reset(id) nel modulo.

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

)) 
+0

Stavo cercando aiuto nel filtrare i dati e generare crosstables e grafici. Gradirei davvero qualsiasi aiuto nel farmi sapere come farlo funzionare. Ho postato la mia domanda e spero che tu sia in grado di suggerire qualche soluzione. Grazie!! Link al mio post è http://stackoverflow.com/questions/41187194/shiny-dynamic-filter-variable-selection-and-display-of-variable-values-for-selec – user1412

+0

Grazie Dean, pensi che sia possibile aggiungere la tua funzione direttamente nei pacchetti lucidi o shinydashboards? –

+1

@DimitriPetrenko intendi spostare la funzione di reset in lucida? Non penso che succederà. Puoi chiedere a rstudio a riguardo, se lo desiderano. Ma shinyjs ha molte altre funzioni altrettanto utili quindi penso che abbia senso tenere insieme i pacchetti –

0

Questa è un'altra opzione che funziona per gli input statici o dinamici e non riguarda interamente gli input di re-rendering.

Esso utilizza:

reactiveValuesToList per ottenere tutti i valori iniziali, e (opzionalmente) tutti i valori di ingresso dinamici che vengono inizializzate in seguito.

session$sendInputMessage per aggiornare i valori per gli ingressi generici. Le funzioni updateXyzInput chiamano questo sotto il cofano come session$sendInputMessage(inputId, list(value = x, ...).

Ogni input Shiny utilizza value per il suo messaggio di input e quasi tutti verranno aggiornati con il loro valore di input così com'è.Solo due ingressi che ho trovato hanno bisogno di un involucro speciale - checkboxGroupInput per non inviare NULL quando non è selezionato nulla e dateRangeInput per convertire il numero c(start, end) in uno list(start = start, end = end).

Potrebbe non essere una buona idea resettare ciecamente TUTTI gli ingressi (anche le schede verranno ripristinate), ma questo può essere facilmente adattato per ripristinare un insieme filtrato di ingressi.

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)