2014-10-17 6 views
9

Hinweis: Nachdem ich die Antwort gefunden hatte, formulierte ich die Frage neu, um sie klarer zu machen.Kann ich den alten Wert eines reaktiven Objekts speichern, wenn es sich ändert?

Manchmal in einer shiny App. Ich möchte einen Wert verwenden, der vom Benutzer für ein Widget ausgewählt wurde, sowie den vorherigen Wert, der für dasselbe Widget ausgewählt wurde. Dies könnte für reaktive Werte gelten, die von Benutzereingaben abgeleitet werden, wobei ich den alten und den neuen Wert haben möchte.

Das Problem ist, dass, wenn ich versuche, den Wert eines Widgets zu speichern, die Variable, die diesen Wert enthält, reaktiv sein muss oder nicht bei jeder Änderung des Widgets aktualisiert wird. Aber wenn ich den Wert in einem reaktiven Kontext speichere, gibt es immer den aktuellen Wert, nicht den vorherigen.

Wie kann ich den vorherigen Wert eines Widgets speichern, aber jedes Mal aktualisieren, wenn der Benutzer das Widget ändert?

Gibt es einen Weg, der die Verwendung eines actionButton nicht jedes Mal erfordert, wenn der Benutzer etwas ändert? Die Vermeidung einer actionButton kann wünschenswert sein, mit dem Hinzufügen von einem ist sonst nicht notwendig und schafft überschüssiges Klicken für den Benutzer.

+0

Ihr Code hat Fehler –

+0

@MatthewPlourde Danke - Ich habe die Frage bearbeitet und am Ende meine eigene Antwort herauszufinden. Die Frage hat keinen Code mehr. –

+0

Können Sie keine globale Variable verwenden, die vor 'server' definiert ist? Dann innerhalb des Servers, Werte in diese globale Variable speichern mit << - – Heisenberg

Antwort

3

Da die Session-Flush-Event-Methode für diesen Zweck zu brechen scheint, ist hier eine alternative Möglichkeit, es mit einem observeEvent Konstrukt und einer reaktiven Variablen zu tun.

library(shiny) 

ui <- fluidPage(
    h1("Memory"), 
    sidebarLayout(
    sidebarPanel(
     numericInput("val", "Next Value", 10) 
    ), 
    mainPanel(
     verbatimTextOutput("curval"), 
     verbatimTextOutput("lstval") 
    ) 
) 
) 

server <- function(input,output,session) { 
    rv <- reactiveValues(lstval=0,curval=0) 

    observeEvent(input$val, {rv$lstval <- rv$curval; rv$curval <- input$val}) 

    curre <- reactive({req(input$val); input$val; rv$curval}) 
    lstre <- reactive({req(input$val); input$val; rv$lstval}) 

    output$curval <- renderPrint({sprintf("cur:%d",curre())}) 
    output$lstval <- renderPrint({sprintf("lst:%d",lstre())}) 
} 
options(shiny.reactlog = TRUE) 
shinyApp(ui, server) 

Nachgeben:

enter image description here

+0

Was meinst du mit "globale Variable" hier? Du scheinst nichts in 'gloabl.r' zu definieren. –

+0

Ja, eine schlampige aber gebräuchliche Verwendung des Begriffs "globale Variable". Korrigiert es. –

+0

Err, stellt sich heraus, dass Sie den Operator '<< -' nicht verwenden müssen, wenn Sie eine reaktive Variable verwenden. Cool. Danke, dass du mich angestupst hast. –

7

aktualisieren Diese Antwort wurde vor dem Aufkommen des in shinyreactiveValues/observeEvent Modell veröffentlicht. Ich denke, dass die Antwort von @MikeWise der bessere Weg ist, dies zu tun.

Nach etwas Herumspielen ist das, was ich gefunden habe. Die ui.r ist nichts Besonderes

ui.r

library(shiny) 

ui <- shinyUI(fluidPage(
    sidebarLayout(
    sidebarPanel(
     selectizeInput(inputId="XX", label="Choose a letter",choices=letters[1:5]) 
    ), 
    mainPanel(
     textOutput("Current"), 
     textOutput("old") 
    ) 
) 
)) 

"Current" wird die aktuelle Auswahl und "old" zeigt die vorherige Auswahl anzuzeigen.

In der server.r habe ich drei Schlüsselfunktionen verwendet: reactiveValues, isolate und session$onFlush.

server.r

library(shiny) 

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

    Values<-reactiveValues(old="Start") 

    session$onFlush(once=FALSE, function(){ 
    isolate({ Values$old<-input$XX }) 
    }) 


    output$Current <- renderText({paste("Current:",input$XX)}) 

    output$old <- renderText({ paste("Old:",Values$old) }) 
} 

Die server.r funktioniert wie folgt.

Zuerst wird Values$old mit der Funktion reactiveValues erstellt. Ich gab ihm den Wert "Start", um klar zu machen, was beim Laden passierte. Dann habe ich eine session$onFlush Funktion hinzugefügt. Beachten Sie, dass ich session als ein Argument in meiner server Funktion habe. Dies wird jedes Mal ausgeführt, wenn das reaktive System durchleuchtet wird - beispielsweise wenn der Benutzer die selectizeInput ändert. Wichtig ist, dass es ausgeführt wird, bevor input$XX einen neuen Wert erhält - der Wert hat sich also unter selectizeInput geändert, aber nicht unter XX.

Innerhalb der session$onFlush ich dann den ausgehenden Wert von XX zu Values$old zuweisen. Dies wird in einem isolate() getan, da dies verhindert, dass Probleme mit input$XX mit den neuen Werten aktualisiert wird.Ich kann dann input$XX und Values$old in den renderText() Funktionen verwenden.

+0

Es scheint, dass das Skript nicht funktioniert. Ich habe den gleichen Wert für Old und Current. –

+0

Gebrochen. Es sieht so aus, als ob etwas Wesentliches für das Funktionieren geändert wurde. –

+0

@MikeWise Danke, das wurde vor 'observeEvent' geschrieben, also ist es jetzt veraltet. –

Verwandte Themen