2016-05-29 2 views
3

Ich versuche, uiOutput Elemente mit einem Index hinzufügen und entfernen, um jedes einzelne Element zu verfolgen. Es gibt eine actionButton für das Hinzufügen und das Element der Liste, und eine x Schaltfläche für jedes Element, das das ausgewählte Element entfernt, wie im Bild unten:Dynamische Hinzufügen und Entfernen von uiOutput-Elementen basierend auf Index mit actionButtons

Shiny dynamic elements example

Ich bin ein einziges .Rmd mit Datei, die sowohl ui als auch server Code enthält. Meine aktuelle Lösung (mit denen ich kann die gewünschte Funktionalität nicht produziert oben gezeigt --- es im Grunde nichts tut) ist die folgende:

actionButton("addFilter", "Add filter", icon=icon("plus", class=NULL, lib="font-awesome")) 

i <- 0 

observeEvent(input$addFilter, { 
    i <<- i + 1 
    uiOutput(paste("filterPage",i,sep="")) 

    output[[paste("filterPage",i,sep="")]] = renderUI({ 
    fluidPage(
     fluidRow(
     column(6, selectInput(paste("filteringFactor",i,sep=""), "Choose factor to filter by:", 
           choices=c("factor A", "factor B", "factor C"), selected="factor B", 
           width="100%")), 
     column(6, actionButton(paste("removeFactor",i,sep=""), "", 
           icon=icon("times", class = NULL, lib = "font-awesome"))) 
    ) 
    ) 
    }) 

    observeEvent(input[[paste("removeFactor",i,sep="")]], { 
    output[[paste("filterPage",i,sep="")]] = renderUI({}) 
    }) 

}) 

Als ich uiOutput setzen und die Entfernen-Taste observeEvent außerhalb der Add-Taste observeEvent der Code funktioniert, aber ich brauche eine gesonderte Erklärung pro Index haben, wie folgt:

uiOutput(paste("filterPage",1,sep="")) 
uiOutput(paste("filterPage",2,sep="")) 
uiOutput(paste("filterPage",3,sep="")) 
uiOutput(paste("filterPage",4,sep="")) 

actionButton("addFilter", "Add filter", icon=icon("plus", class=NULL, lib="font-awesome")) 

i <- 0 

observeEvent(input$addFilter, { 
    i <<- i + 1 
    output[[paste("filterPage",i,sep="")]] = renderUI({ 
    fluidPage(
     fluidRow(
     column(6, selectInput(paste("filteringFactor",i,sep=""), "Choose factor to filter by:", 
           choices=c("factor A", "factor B", "factor C"), selected="factor B", 
           width="100%")), 
     column(6, actionButton(paste("removeFactor",i,sep=""), "", 
           icon=icon("times", class = NULL, lib = "font-awesome"))) 
    ) 
    ) 
    }) 
}) 

observeEvent(input[[paste("removeFactor",1,sep="")]], { 
    output[[paste("filterPage",1,sep="")]] = renderUI({}) 
}) 
observeEvent(input[[paste("removeFactor",2,sep="")]], { 
    output[[paste("filterPage",2,sep="")]] = renderUI({}) 
}) 
observeEvent(input[[paste("removeFactor",3,sep="")]], { 
    output[[paste("filterPage",3,sep="")]] = renderUI({}) 
}) 
observeEvent(input[[paste("removeFactor",4,sep="")]], { 
    output[[paste("filterPage",4,sep="")]] = renderUI({}) 
}) 

ich nicht eine for-Schleife oder lapply Aufruf zu arbeiten (es sieht aus wie ein Scoping-Problem, das ich nicht verstehe) machen könnte . Da die Anzahl der Elemente nicht im Voraus bekannt ist, werden die Werte für mich nicht funktionieren. Weiß jemand, wie das funktioniert? Vielen Dank.

Antwort

3

Ich habe eine Lösung für Sie, die auf dem Backend vielleicht nicht schön ist, aber das Leben sehr einfach macht. Ich würde vorschlagen, dass Sie alle Ihre Elemente ineinander verschachteln. Machen Sie die uiOutput Nummer i enthalten die uiOutput für die nächste. Auf diese Weise können Sie sie nacheinander hinzufügen, ohne sich um die Größe oder die Gesamtzahl der Elemente kümmern zu müssen. Leistungsmäßig wird dies auch in Ordnung sein, zumal ich glaube nicht, dass Sie Tausende von Filtern erstellen. Siehe Code für weitere Details.

Zum Löschen haben Sie bereits gesehen, dass es mühsam ist, alle Tasteneingabewerte zu verfolgen. Daher würde ich vorschlagen, dass Sie eine Variable zum Beobachten entwerfen, die Ihnen die Elementnummer angibt, auf die geklickt wurde. Wir können dies mit der benutzerdefinierten Funktion onclick für unsere Tasten erreichen, indem wir die Tastennummer an eine einzige Eingangsvariable senden. Vielleicht möchten Sie sich mit der JavaScript-Clientfunktion Shiny.onInputChange vertraut machen. Nur kurz: Es sendet einen Wert an das R-Backend unter dem gegebenen Variablennamen.

Das Löschen des entsprechenden ui-Elements ist einfach.

Wenn Sie mehr darüber erfahren und eine klarere, feinere Lösung entwerfen möchten, versuchen Sie this page und verwandte Fragen. Dort können Sie Informationen darüber erhalten, wie Sie dynamische UI-Abschnitte in einem Dokument ohne den häufig verwendeten einzelnen uiOutput-Wrapper entwerfen und hinzufügen können.

Code (Ich habe eine reguläre ui-Server-Anwendung):

library(shiny) 

ui <- shinyUI(
    fluidPage(

    actionButton("addFilter", "Add filter", icon=icon("plus", class=NULL, lib="font-awesome")), 

    uiOutput("filterPage1") 
) 
) 

server <- function(input, output){ 
    i <- 0 

    observeEvent(input$addFilter, { 
    i <<- i + 1 
    output[[paste("filterPage",i,sep="")]] = renderUI({ 
     list(
     fluidPage(
      fluidRow(
      column(6, selectInput(paste("filteringFactor",i,sep=""), "Choose factor to filter by:", 
           choices=c("factor A", "factor B", "factor C"), selected="factor B", 
           width="100%")), 
      column(6, actionButton(paste("removeFactor",i,sep=""), "", 
           icon=icon("times", class = NULL, lib = "font-awesome"), 
           onclick = paste0("Shiny.onInputChange('remove', ", i, ")"))) 
     ) 
     ), 
     uiOutput(paste("filterPage",i + 1,sep="")) 
    ) 
    }) 
    }) 

    observeEvent(input$remove, { 
    i <- input$remove 

    output[[paste("filterPage",i,sep="")]] <- renderUI({uiOutput(paste("filterPage",i + 1,sep=""))}) 
    }) 
} 

shinyApp(ui, server) 
+0

Amazing! Vielen Dank! –

Verwandte Themen