2016-08-15 4 views
6

私は、私が解決策を見つけることができなかった非常に単純なユーザケースであると思っている:私はShinyがユーザ指定の入力数を生成し、それぞれを観察する。動的な入力数のためのオブザーバを生成する

以下の最小限の再現可能なコードでは、ユーザはtextInputウィジェットに入力することによって、必要なアクションボタンの数を示します。彼または彼女はその後、アクションボタンを生成する "submit"を押します。次に、ユーザは、(単にボタンの名前を印刷し、最小限のケース用など)を任意のアクションボタンをクリックすると、それに特定の出力を生成できるようにするために私が欲しいもの

は次のとおりです。

library("shiny") 

ui <- fluidPage(textInput("numButtons", "Number of buttons to generate"), 
       actionButton("go", "Submit"), uiOutput("ui")) 

server <- function(input, output) { 

     makeObservers <- reactive({ 

       lapply(1:(as.numeric(input$numButtons)), function (x) { 

         observeEvent(input[[paste0("add_", x)]], { 

           print(paste0("add_", x)) 

         }) 

       }) 
     }) 

     observeEvent(input$go, { 

       output$ui <- renderUI({ 

         num <- as.numeric(isolate(input$numButtons)) 

         rows <- lapply(1:num, function (x) { 

           actionButton(inputId = paste0("add_", x), 
             label = paste0("add_", x)) 

         }) 

         do.call(fluidRow, rows) 

       }) 

       makeObservers() 

     }) 


} 

shinyApp(ui, server) 

上記のコードの問題は、何人かのオブザーバが何らかの形で作成されていることですが、すべてが入力として、リスト内の最後の項目だけがlapplyに渡されます。だから私が4つのアクションボタンを生成し、アクションボタン#4をクリックすると、シャイニーはその名前を4回印刷しますが、他のボタンはすべて反応しません。 lapplyを使用してオブザーバーを生成する

アイデアは、すべてがそう長くactionButtonは一度だけ押された正常に動作しますあなたの例ではhttps://github.com/rstudio/shiny/issues/167#issuecomment-152598096

+0

これは「lapply」にリスト過去にのみ、最後の項目のオブザーバーを生成する問題は光沢があり、Rのバージョン間の互換性の一つであったということだけであるノート私がインストールしたRの最新バージョンでは、私のサンプルコードは以下のように動作し、それがそうであると言い、解決策が提供されます。 –

答えて

4

から来ています。たとえば、3のボタン/オブザーバーを作成すると、コンソールに正しいIDが表示されます。生成された新しいactionButtonごとに1人のオブザーバーが存在します。私は3以外の番号を選択してから、再度submitを押すと√

[1] "add_1" 
[1] "add_2" 
[1] "add_3" 

しかし、あなたは説明した問題が開始されます。

と言っています。4アクションボタン - 4を入力し、submitを入力してください。その後、私はそれぞれの新しい生成ボタンを一回押すと、私は次の出力を得る:submitボタンをクリックすると

[1] "add_1" 
[1] "add_1" 
[1] "add_2" 
[1] "add_2" 
[1] "add_3" 
[1] "add_3" 
[1] "add_4" 

を、私は再び最初の3つのボタンのオブザーバーを作成した - 私は、最初の三つのボタンには2人のオブザーバーを持っているだけ新しい4番目のボタンの1つ。

私たちはこのゲームを続けてプレイすることができ、各ボタンのオブザーバーがますます増えます。以前よりも少数のボタンを作成した場合と非常によく似ています。これに


ソリューションは、新しいもののためにオブザーバーを生成するために、アクションボタンがすでに定義されているのを追跡することとなります。下の例では、これをどのように行うことができるかを示しました。それは最良にプログラムされていないかもしれませんが、そのアイデアを示すためにはうまくいくはずです。

全例:

library("shiny") 

ui <- fluidPage(
    numericInput("numButtons", "Number of buttons to generate", 
       min = 1, max = 100, value = NULL), 
    actionButton("go", "Submit"), 
    uiOutput("ui") 
) 

server <- function(input, output) { 

    # Keep track of which observer has been already created 
    vals <- reactiveValues(x = NULL, y = NULL) 

    makeObservers <- eventReactive(input$go, { 

    IDs <- seq_len(input$numButtons) 

    # For the first time you press the actionButton, create 
    # observers and save the sequence of integers which gives 
    # you unique identifiers of created observers 
    if (is.null(vals$x)) { 
     res <- lapply(IDs, function (x) { 
     observeEvent(input[[paste0("add_", x)]], { 
      print(paste0("add_", x)) 
     }) 
     }) 
     vals$x <- 1 
     vals$y <- IDs 
    print("else1") 

    # When you press the actionButton for the second time you want to only create 
    # observers that are not defined yet 
    # 

    # If all new IDs are are the same as the previous IDs return NULLL 
    } else if (all(IDs %in% vals$y)) { 
     print("else2: No new IDs/observers") 
     return(NULL) 

    # Otherwise just create observers that are not yet defined and overwrite 
    # reactive values 
    } else { 
     new_ind <- !(IDs %in% vals$y) 
     print(paste0("else3: # of new observers = ", length(IDs[new_ind]))) 
     res <- lapply(IDs[new_ind], function (x) { 
      observeEvent(input[[paste0("add_", x)]], { 
      print(paste0("add_", x)) 
      }) 
     }) 
     # update reactive values 
     vals$y <- IDs 
    } 
    res 
    }) 


    observeEvent(input$go, { 

    output$ui <- renderUI({ 

     num <- as.numeric(isolate(input$numButtons)) 

     rows <- lapply(1:num, function (x) { 

     actionButton(inputId = paste0("add_", x), 
        label = paste0("add_", x)) 

     }) 

     do.call(fluidRow, rows) 

    }) 
    makeObservers() 
    }) 

} 
shinyApp(ui, server) 
関連する問題