2017-08-24 143 views
0

這是以前查詢的擴展[Creating asymmetric layouts involving rows and column in Shiny。我正在嘗試創建一個動態UI輸出。需要通過將每個「主題」的下拉菜單和文本框分組在一起來修復佈局,以及如何從各種下拉菜單和動態創建的文本框中捕獲數據。RShiny中的動態表格

這是從以前的查詢[How to add/remove input fields dynamically by a button in shiny修改後的代碼:

library(shiny) 

ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"), 
actionButton("rm_btn", "Remove Textbox"), 
textOutput("counter") 
), 
mainPanel(
    fluidRow(column(6,uiOutput("selectbox_ui"), offset = 0), 
column(6,fluidRow(column(6,uiOutput("textbox_ui1"), uiOutput("textbox_ui2"))), 
    fluidRow(column(6,uiOutput("textbox_ui3"), uiOutput("textbox_ui4"),offset = 0)), offset = 0) 
) 
))) 

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

# Track the number of input boxes to render 
counter <- reactiveValues(n = 0) 

observeEvent(input$add_btn, {counter$n <- counter$n + 1}) 
observeEvent(input$rm_btn, {if (counter$n > 0) counter$n <- counter$n - 1}) 

output$counter <- renderPrint(print(counter$n)) 

textboxes1 <- reactive({n <- counter$n 
if (n > 0) 
    {lapply(seq_len(n), function(i) {textInput(inputId = paste0("textin1", i),label = paste0("Textbox_A_Topic", i), value = "Hello World!")})} 
}) 

textboxes2 <- reactive({n <- counter$n 
    if (n > 0) 
    {lapply(seq_len(n), function(i) {textInput(inputId = paste0("textin2", i),label = paste0("Textbox_B_Topic", i), value = "Hello World!")} )} 
}) 
textboxes3 <- reactive({n <- counter$n 
    if (n > 0) 
    {lapply(seq_len(n), function(i) {textInput(inputId = paste0("textin3", i),label = paste0("Textbox_C_Topic", i), value = "Hello World!")} )} 
}) 
textboxes4 <- reactive({n <- counter$n 
    if (n > 0) 
    {lapply(seq_len(n), function(i) {textInput(inputId = paste0("textin4", i),label = paste0("Textbox_D_Topic", i), value = "Hello World!")} )} 
}) 
selectboxes <- reactive({n <- counter$n 
    if (n > 0) 
    {lapply(seq_len(n), function(i) {selectInput(inputId = paste0("selectTopic", i), label = paste0("Topic", i), 
               choices = c("one", "two", "three"), selected = "two", multiple = FALSE)})} 
}) 

output$textbox_ui1 <- renderUI(textboxes1()) 
output$textbox_ui2 <- renderUI({textboxes2() }) 
output$textbox_ui3 <- renderUI({textboxes3() }) 
output$textbox_ui4 <- renderUI({textboxes4() }) 
output$selectbox_ui <- renderUI({selectboxes()}) 

}) 

回答

1

爲了解決佈局問題,它有助於想想都涉及到一個主題元素(即下拉菜單和四個文本輸入)組成一個單元塊。然後找到一種方法來創建這些塊中的一個(也可能是將該過程抽取到函數中的一個好主意),然後繼續堆疊塊以獲得所需的結果。

一種用來在你的榜樣一個完整的話題塊可能看起來像這樣的功能:

topic_ui <- function(i) { 

    # render all elements related to a single topic into one div 

    fluidRow(

    # drop-down select menu on the left 
    column(width = 6, offset = 0, 
     selectInput(
     inputId = paste0("selectTopic", i), 
     label = paste0("Topic", i), 
     choices = c("one", "two", "three"), 
     selected = "two", 
     multiple = FALSE 
    ) 
    ), 

    # text boxes on the right 
    column(width = 6, offset = 0, 
     lapply(LETTERS[1:4], function(l) { 
     textInput(
      inputId = paste0("textin", l, i), 
      label = paste0("Textbox_", l, "_Topic", i), 
      value = "Hello World!" 
     ) 
     }) 
    ) 

) 

} 

現在是修改服務器的新主題UI製作功能工作的問題:

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

    session$onSessionEnded(stopApp) 

    # Track the number of input boxes to render 
    counter <- reactiveValues(n = 0) 

    observeEvent(input$add_btn, { 
    counter$n <- counter$n + 1 
    }) 

    observeEvent(input$rm_btn, { 
    if (counter$n > 0) 
     counter$n <- counter$n - 1 
    }) 

    output$counter <- renderPrint(print(counter$n)) 

    # render a number of topic ui elements based on the counter, 
    # each consisting of a selectInput and four textInputs 
    topics <- reactive({ 
    n <- counter$n 
    if (n > 0) 
     lapply(seq_len(n), topic_ui) 
    }) 

    output$topic_ui <- renderUI(topics()) 

}) 

最後,在UI側也可以簡化爲一個結果:

ui <- shinyUI(fluidPage(

    sidebarPanel(

    actionButton("add_btn", "Add Textbox"), 
    actionButton("rm_btn", "Remove Textbox"), 
    textOutput("counter") 

), 

    mainPanel(

    # dynamically created ui elements 

    uiOutput("topic_ui") 

) 

)) 

至於捕獲來自動態元素的輸入,原則上,您只需按照與任何靜態輸入元素相同的方式執行操作:通過inputId參數中給出的名稱引用它。作爲一種複雜情況,我想你必須包含一些檢查,以確定動態元素是否首先存在。如果您擴展您的示例案例以包含您想要對動態輸入進行的操作,則可以嘗試再次查看!

+0

我現在面臨的問題是,在填寫文本框後,當我點擊添加按鈕添加更多數據時,會使用'Hello world'值創建一組全新的文本框,以替換輸入的值文本框。 – RanonKahn

+0

我可以考慮兩種解決方法:將所有輸入元素的當前狀態保存在被動列表中,然後在添加或刪除框時使用這些狀態重新創建舊輸入(正如我在https末尾推測的那樣: //stackoverflow.com/a/31457114/4550695);或者如果您擁有最多的主題,只需立即創建所有主題,並使用'shinyjs'根據計數器值動態顯示和隱藏它們,而不是實際添加和刪除它們。 –

+0

我正在與第二個選項。 – RanonKahn