难以设置具有嵌套反应性的动态UI

时间:2018-03-14 09:29:34

标签: r dynamic shiny nested shiny-reactivity

首先,这是一个可运行的例子:

library(shiny)
library(shinyjs)
library(dplyr)

###################################################################################

MTX_UI <- fluidPage(
    fluidRow(column(6, titlePanel("Calculator"))),
    fluidRow(numericInput("Ninf", "Ninf", 1,
                          min = 1, max = 12, step = 1) %>% column(., width = 3)),
    tags$div(id = "InfPanel"),
    hr(),
    fluidRow(column(3, actionButton("calculate", "Calculate")))
)

###################################################################################

MTX_Server <- function(input, output, session) {

  #UI creation
    change_Ninf <- reactive({input[["Ninf"]]})
    ExistNinf <<- 0

  #Creating inf panels
    observeEvent(change_Ninf(), {
      Ninf <- change_Ninf()
      if (Ninf>ExistNinf) {    
        #Decide list to insert
          if (ExistNinf==0) {lstToIns <- seq(Ninf)} else {lstToIns <- seq(Ninf)[-seq(ExistNinf)]}
        #Update list inserted
          ExistNinf <<- Ninf
        #Insert UI & reactive component
          for (InfN in lstToIns) {
            #Insert UI
              insertUI(
                selector = '#InfPanel',
                ui = conditionalPanel(paste0("input.Ninf >= ", InfN),
                                      hr(),
                                      wellPanel(
                                        fluidRow(column(3, titlePanel(paste0("Inf #", InfN)))),
                                        fluidRow(column(3, numericInput(paste0("Nobs_", InfN),
                                                                        "Nobs:", 2, min = 2, max = 12, step = 1)),
                                                 column(3, textInput(paste0("Var10_", InfN), "Var10:", 12)),
                                                 column(3, textInput(paste0("Var11_", InfN), "Var11:", 1.3)),
                                                 column(3, textInput(paste0("Var12_", InfN), "Var12:", 6))
                                        ),
                                        fluidRow(column(2, "VAR1:"),
                                                 column(2, "VAR2:"),
                                                 column(1, "VAR3:"),
                                                 column(1, "VAR4:"),
                                                 column(2, "VAR5:"),
                                                 column(1, "VAR6:"),
                                                 column(1, "VAR7:")
                                        ),
                                        fluidRow(
                                          column(1, offset = 4, checkboxInput(paste0("fix_VAR3_", InfN), "Same", FALSE)),
                                          column(1, checkboxInput(paste0("fix_VAR4_", InfN), "Same", FALSE)),
                                          column(2, checkboxInput(paste0("fix_VAR5_", InfN), "Same", FALSE)),
                                          column(1, checkboxInput(paste0("fix_VAR6_", InfN), "Same", FALSE)),
                                          column(1, checkboxInput(paste0("fix_VAR7_", InfN), "Same", FALSE))
                                        ),
                                        tags$div(id = paste0("ObsPanel_", InfN))
                                      ))
              )
            #Create fixation reactive components
              assign(paste0("react_fix_VAR3_", InfN), reactive({input[[paste0("fix_VAR3_", InfN)]]}), inherits = T)
              assign(paste0("react_fix_VAR4_", InfN), reactive({input[[paste0("fix_VAR4_", InfN)]]}), inherits = T)
              assign(paste0("react_fix_VAR5_", InfN), reactive({input[[paste0("fix_VAR5_", InfN)]]}), inherits = T)
              assign(paste0("react_fix_VAR6_", InfN), reactive({input[[paste0("fix_VAR6_", InfN)]]}), inherits = T)
              assign(paste0("react_fix_VAR7_", InfN), reactive({input[[paste0("fix_VAR7_", InfN)]]}), inherits = T)
            #Update Obs reactive components
              assign(paste0("change_Nobs_", InfN), reactive({input[[paste0("Nobs_", InfN)]]}), inherits = T)
            #Creating Obs components
              if (!exists(paste0("ExistNobs_", InfN))) {assign(paste0("ExistNobs_", InfN), 0)}
              observeEvent(get(paste0("change_Nobs_", InfN))(), {
                Nobs <- get(paste0("change_Nobs_", InfN))()
                ExistNobs <- get(paste0("ExistNobs_", InfN))
                if (Nobs>ExistNobs) {
                  #Decide list to insert
                    if (ExistNobs==0) {lstToIns_obs <- seq(Nobs)} else {lstToIns_obs <- seq(Nobs)[-seq(ExistNobs)]}
                  #Update list inserted
                    assign(paste0("ExistNobs_", InfN), Nobs, inherits = T)
                  #Insert UI
                    for (ObsN in lstToIns_obs) {
                      if (ObsN==1) {
                        insertUI(
                          selector = paste0("#ObsPanel_", InfN),
                          ui = conditionalPanel(paste0("input.Nobs_", InfN, " >= ", 1),
                                                fluidRow(
                                                  column(2, textInput(paste0("VAR1_", InfN, "_", 1), NULL, 0)),
                                                  column(2, textInput(paste0("VAR2_", InfN, "_", 1), NULL, 0)),
                                                  column(1, textInput(paste0("VAR3_", InfN, "_", 1), NULL, 1)),
                                                  column(1, textInput(paste0("VAR4_", InfN, "_", 1), NULL, 1)),
                                                  column(2, textInput(paste0("VAR5_", InfN, "_", 1), NULL, 1)),
                                                  column(1, textInput(paste0("VAR6_", InfN, "_", 1), NULL, 1)),
                                                  column(1, textInput(paste0("VAR7_", InfN, "_", 1), NULL, 1))
                                                ))
                        )
                        shinyjs::useShinyjs()
                        shinyjs::disable(paste0("VAR1_", InfN, "_1"))
                        shinyjs::disable(paste0("VAR2_", InfN, "_1"))
                      } else {
                        insertUI(
                          selector = paste0("#ObsPanel_", InfN),
                          ui = conditionalPanel(paste0("input.Nobs_", InfN, " >= ", ObsN),
                                                fluidRow(
                                                  column(2, textInput(paste0("VAR1_", InfN, "_", ObsN), NULL, 1)),
                                                  column(2, textInput(paste0("VAR2_", InfN, "_", ObsN), NULL, 1)),
                                                  column(1, textInput(paste0("VAR3_", InfN, "_", ObsN), NULL, 1)),
                                                  column(1, textInput(paste0("VAR4_", InfN, "_", ObsN), NULL, 1)),
                                                  column(2, textInput(paste0("VAR5_", InfN, "_", ObsN), NULL, 1)),
                                                  column(1, textInput(paste0("VAR6_", InfN, "_", ObsN), NULL, 1)),
                                                  column(1, textInput(paste0("VAR7_", InfN, "_", ObsN), NULL, 1))
                                                ))
                        )
                        local({
                          observeEvent(get(paste0("react_fix_VAR3_", InfN))(), {
                            shinyjs::toggleState(paste0("VAR3_", InfN, "_", ObsN), !(get(paste0("react_fix_VAR3_", InfN))()))
                          })
                          observeEvent(get(paste0("react_fix_VAR4_", InfN))(), {
                            shinyjs::toggleState(paste0("VAR4_", InfN, "_", ObsN), !(get(paste0("react_fix_VAR4_", InfN))()))
                          })
                          observeEvent(get(paste0("react_fix_VAR5_", InfN))(), {
                            shinyjs::toggleState(paste0("VAR5_", InfN, "_", ObsN), !(get(paste0("react_fix_VAR5_", InfN))()))
                          })
                          observeEvent(get(paste0("react_fix_VAR6_", InfN))(), {
                            shinyjs::toggleState(paste0("VAR6_", InfN, "_", ObsN), !(get(paste0("react_fix_VAR6_", InfN))()))
                          })
                          observeEvent(get(paste0("react_fix_VAR7_", InfN))(), {
                            shinyjs::toggleState(paste0("VAR7_", InfN, "_", ObsN), !(get(paste0("react_fix_VAR7_", InfN))()))
                          })
                        })
                      }
                    }
                }
              })
          }
      }
    })
}

###################################################################################

shinyApp(MTX_UI, MTX_Server)

我期待以下内容:

  
      
  1. 当用户更改Ninf(位于应用顶部)时,显示的Inf wellPanel数会相应更改。 (顶层反应)
  2.   
  3. 对于每个Inf wellPanel,当用户更改Nobs时,要输入的观察行数将相应更改。 (第二层反应)
  4.   
  5. 生成每个Inf wellPanel时,应自动禁用textInputVAR1下的每个VAR2框(shinyjs::disable)。< / LI>   
  6. 对于每个Inf wellPanel,当选中SameVAR3的每个VAR7框时,textInput下面的VARxshinyjs::toggleState应禁用(除第一个之外)(max.Ninf=12)。 (第3层反应)
  7.   

到目前为止,我成功了#1和#2。但到目前为止,我努力实现#3和#4的努力是徒劳的,而且还有很多困难......

我开始对所有内容进行硬编码(使用max.Nobs=12insertUI)但事实证明加载时间很长,因为它必须一次加载所有对象 - 事实上,通常是用户只会使用前两个Inf面板。所以我转向这种嵌套结构方法并尝试使用function check() { if(usertype==null) { alert('please select user type'); } else { $('#registerusers').hide(); if(usertype=='individual') { $('#agent').html(); $('#vendor').html(); $('#service').html(); $('#'+usertype).append('<div class="tab">Name: <p><input placeholder="First name..." oninput="this.className = ''"></p> <p><input placeholder="Last name..." oninput="this.className = ''"></p> </div> <div class="tab">Contact Info: <p><input placeholder="E-mail..." oninput="this.className = ''"></p> <p><input placeholder="Phone..." oninput="this.className = ''"></p> </div> <div class="tab">Birthday: <p><input placeholder="dd" oninput="this.className = ''"></p> <p><input placeholder="mm" oninput="this.className = ''"></p> <p><input placeholder="yyyy" oninput="this.className = ''"></p> </div> <div class="tab">Login Info: <p><input placeholder="Username..." oninput="this.className = ''"></p> <p><input placeholder="Password..." oninput="this.className = ''"></p> </div> <div style="overflow:auto;"> <div style="float:right;"> <button type="button" id="prevBtn" onclick="nextPrev(-1)">Previous</button> <button type="button" id="nextBtn" onclick="nextPrev(1)">Next</button> </div> </div> <!-- Circles which indicates the steps of the form: --> <div style="text-align:center;margin-top:40px;"> <span class="step"></span> <span class="step"></span> <span class="step"></span> <span class="step"></span> </div> '); $('#'+usertype).removeClass('hid'); } else if(usertype=='agent') { $('#individual').html(); $('#vendor').html(); $('#service').html(); $('#'+usertype).html('<h2> as</h2>'); $('#'+usertype).removeClass('hid'); } alert(usertype); } } 。但是上面的问题阻碍了我前进。

谢谢!

0 个答案:

没有答案