2016-08-15 18 views
6

Tôi có một trường hợp người dùng khá đơn giản mà tôi không thể tìm được giải pháp cho: Tôi muốn Sáng tạo để tạo số lượng đầu vào do người dùng chỉ định, tự động tạo người quan sát cho mỗi người.Tạo các nhà quan sát cho số đầu vào động

Trong mã có thể tái sản xuất tối thiểu bên dưới, người dùng cho biết số lượng nút tác vụ mong muốn bằng cách nhập vào tiện ích textInput; sau đó anh ta nhấn "submit", tạo ra các nút hành động.

Những gì tôi muốn là cho người sử dụng để sau đó có thể nhấp vào bất kỳ nút hành động và tạo ra một sản lượng cụ thể cho nó (ví dụ như đối với trường hợp tối thiểu, chỉ in tên của nút):

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) 

Vấn đề với mã ở trên là bằng cách nào đó một số nhà quan sát được tạo ra, nhưng tất cả họ đều lấy làm đầu vào của họ chỉ mục cuối cùng trong danh sách được chuyển đến lapply. Vì vậy, nếu tôi tạo ra bốn nút hành động, và tôi bấm vào nút hành động # 4, Shiny in tên của nó bốn lần, trong khi tất cả các nút khác không phản ứng.

Ý tưởng để tạo ra các quan sát viên sử dụng lapply đến từ https://github.com/rstudio/shiny/issues/167#issuecomment-152598096

+0

Đây chỉ là một lưu ý rằng vấn đề tạo ra các quan sát viên chỉ dành cho mục cuối cùng trong danh sách quá khứ để 'lapply' là một trong những khả năng tương thích giữa Shiny và phiên bản của R mà tôi đã cài đặt. Với phiên bản mới nhất của R, mã ví dụ của tôi hoạt động giống như câu trả lời dưới đây cho biết, và giải pháp được cung cấp có hiệu quả. –

Trả lời

4

Trong ví dụ tất cả mọi thứ của bạn hoạt động tốt quá lâu một actionButton đã được ép một lần duy nhất. Ví dụ, khi tôi tạo các nút 3/quan sát viên, tôi nhận được các ID chính xác được in trong bảng điều khiển - có một người quan sát cho mỗi actionButton mới được tạo ra. √

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

Tuy nhiên, khi tôi chọn số khác hơn 3 và sau đó nhấn submit một lần nữa, vấn đề bạn mô tả bắt đầu.

Nói, tôi muốn bây giờ 4 actionButtons - Tôi nhập 4 và nhấn submit. Sau đó, tôi nhấn một lần mỗi nút mới được tạo ra và tôi nhận được một kết quả như sau:

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

Bằng cách nhấp vào submit nút, tôi tạo ra các quan sát viên cho ba nút đầu tiên một lần nữa - Tôi có hai nhà quan sát cho ba nút và lần đầu tiên chỉ một cho nút thứ tư mới.

Chúng tôi có thể chơi trò chơi này liên tục và sẽ nhận được nhiều người quan sát hơn cho mỗi nút. Nó rất giống nhau khi chúng ta tạo ra một số nút nhỏ hơn trước đây.


Giải pháp này sẽ được theo dõi trong đó các nút hành động đã được đã được xác định và sau đó để tạo ra các quan sát viên chỉ dành cho những người mới. Trong ví dụ bên dưới, tôi đã mô tả cách bạn có thể thực hiện việc này. Nó có thể không được lập trình tốt nhất nhưng nó sẽ phục vụ tốt để hiển thị ý tưởng.

Full dụ:

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) 
Các vấn đề liên quan