2016-08-27 3 views
0

Rの中に動的なユーザーインターフェイスを作成しました。これは、流体の行の環境内に4つのselectizeInputボックスを生成します。 addFilterボタンが選択されている場合、追加の流体列が別の4つのボックスとともに生成されます。Shinyのダイナミックユーザーインターフェイスを連続して生成する

以前に入力された値の保存に関する問題があります。私はユーザーの入力を格納する反応性の値のグループを持っています。これらの値はupdateselectizeのオブザーバーに入力されます。ユーザーがゆっくりとクリックすると、すべて正常に動作します。ただし、ユーザーがすばやくクリックすると、値が消去されることがあります。

これは、スクリプトが新しいインターフェイスを設定するときに、オブザーバーを持つ古いものがかなりレンダリングされていないためです。値はリセットされています。

以下はMWEです。バグを引き起こすには、Add Filterボタンをダブルクリックする必要があります。

Server.R:

library(shiny) 

shinyServer(function(session, input, output) { 

    rValues <- reactiveValues(filter_counter = 1, filter_counter2 = 1, filter_waiter = 1, savedFil_1 = "", savedOp_1 = "", 
          savedCrit_1 = "", savedAO_1 = "") 

    columns <- c("C1", "C2") 

    operators <- c("O1", "O2") 
    values <- c("V1", "V2") 
    andor <- c("&&", "||") 

    observeEvent(input$AddFilter,{ 
    if (rValues[['filter_waiter']] == 1) { 
     # Step 1: Store 
     lapply(1:rValues$filter_counter, function(i) { 
     rValues[[paste0("savedFil_", i)]] <- input[[paste0("fil_", i)]] 
     rValues[[paste0("savedOp_", i)]] <- input[[paste0("filOperators_", i)]] 
     rValues[[paste0("savedCrit_", i)]] <- input[[paste0("filCriteria_", i)]] 
     rValues[[paste0("savedAO_", i)]] <- input[[paste0("andor_", i)]] 
     }) 

     # Step 2: Increment counter 
     rValues$filter_counter <- rValues$filter_counter + 1 

     # Step 3: Set filter waiter 
     rValues[['filter_waiter']] <- 0 
    } 
    }) 

    output$filters <- renderUI({ 
    if (rValues[['filter_waiter']] == 1) { 
     ui <- lapply(1:rValues$filter_counter, function(i) { 
     fluidRow(
      column(4, selectizeInput(paste0("fil_", i), label = NULL, choices = NULL)), 
      column(2, selectizeInput(paste0("filOperators_", i), label = NULL, choices = NULL)), 
      column(4, selectizeInput(paste0("filCriteria_", i), label = NULL, choices = NULL)), 
      column(2, selectizeInput(paste0("andor_", i), label = NULL, choices = NULL))) 
     }) 
     return(ui) 
    } 
    }) 

    ### Create observers for filters 
    observe({ 
    lapply(1:rValues$filter_counter, function(i){ 
     # Update the Selectizes 
     updateSelectizeInput(session, paste0("fil_", i), selected = rValues[[paste0("savedFil_", i)]], choices = columns, server = TRUE) 
     updateSelectizeInput(session, paste0("filOperators_", i), selected = rValues[[paste0("savedOp_", i)]], choices = operators, server = TRUE) 
     updateSelectizeInput(session, paste0("filCriteria_", i), selected = rValues[[paste0("savedCrit_", i)]], choices = values, server = TRUE) 
     updateSelectizeInput(session, paste0("andor_", i), selected = rValues[[paste0("savedAO_", i)]], choices = c("", "&&", "||"), server = TRUE) 
    }) 

    rValues[['filter_waiter']] <- 1 
    }) 
}) 

そしてUI.R:

library(shiny) 

shinyUI(fluidPage(

    # Application title 
    titlePanel("Dynamic SelectizeInput UI"), 

    sidebarLayout(
    sidebarPanel(
     actionButton("AddFilter", label = "Add a Filter"), 
     uiOutput("filters") 
    ), 

    mainPanel(
     h1("") 
    ) 
) 
)) 
+0

コードの書式設定は個人的な好みです。最初の編集は何も改善しなかった。オリジナルにロールバック。 –

+1

@DirtySockSniffer明快さと可読性を向上させることは、編集のために確立された理由です。以前のリビジョンにロールバックします。 –

+1

@ Hack-R - 酔っ払った猿のようなコードを書かないようにするにはどうすればいいですか?さらに、あなたが割り当てを行に書いたからといって、それがその標準を意味するわけではありません。 –

答えて

1

あなたのコードを簡略化することができます。ボタンを選択するたびに新しいコントロールを生成するので、selectizeInputコントロールを更新する必要はありません。 反応変数が多すぎます。グローバル変数に変更します。大域変数を使用しない場合は、隔離変数を使用してください。

library(shiny) 

filter_counter <- 0 
filter_values <- list() 
columns  <- c("C1", "C2") 
operators  <- c("O1", "O2") 
values   <- c("V1", "V2") 
andor   <- c("&&", "||") 

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

    output$filters <- renderUI({ 

     input$AddFilter 
     # Step 1: store filter values 
     if (filter_counter>0) { 
      lapply(1:filter_counter, function(i) { 
      filter_values[[paste0("savedFil_", i)]] <<- input[[paste0("fil_", i)]] 
      filter_values[[paste0("savedOp_", i)]] <<- input[[paste0("filOperators_", i)]] 
      filter_values[[paste0("savedCrit_", i)]] <<- input[[paste0("filCriteria_", i)]] 
      filter_values[[paste0("savedAO_", i)]] <<- input[[paste0("andor_", i)]] 
      }) 
     } 

     # Step 2: Increment counter 
     filter_counter <<- filter_counter + 1 

     # Step 3: generate selectInputs 
     ui <- lapply(1:filter_counter, function(i){ 
      fluidRow(
       column(4,selectizeInput(paste0("fil_", i), label= 'fil', selected = filter_values[[paste0("savedFil_", i)]], choices = columns)), 
       column(2,selectizeInput(paste0("filOperators_", i),label= 'filop', selected = filter_values[[paste0("savedOp_", i)]], choices = operators)), 
       column(4,selectizeInput(paste0("filCriteria_", i),label= 'filcri', selected = filter_values[[paste0("savedCrit_", i)]], choices = values)), 
       column(2,selectizeInput(paste0("andor_", i),label= 'andor', selected = filter_values[[paste0("savedAO_", i)]], choices = c("", "&&", "||"))) 
     ) 
     }) 

    }) 
}) 


ui <- shinyUI(fluidPage(

    # Application title 
    titlePanel("Dynamic SelectizeInput UI"), 

    sidebarLayout(
    sidebarPanel(
     actionButton("AddFilter", label = "Add a Filter"), 
     uiOutput("filters") 
    ), 

    mainPanel(
     h1("") 
    ) 
) 
)) 

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