处理嵌套的selectizeInputs和模块

时间:2016-11-03 15:05:16

标签: r shiny

我遇到嵌套selectizeInputs的麻烦,即一组选择输入,其中第一个选择决定第二个选择,控制第三个选择,依此类推。

假设我有一个select1可以让你选择一个数据集,而select2可以让你在数据集中选择一个变量。显然,select2中的选项取决于select1中的选择。我发现如果用户从select2中选择一个变量,然后更改select1,它就不会立即从select2中删除该值,而是通过select1中的新值和旧值进行反应序列。来自select2,它突然引用不同数据集中的变量,这是一个问题。

示例:

library(shiny)

ui =fluidPage(
  selectizeInput('d',choices=c('mtcars','iris'),
                 label="Datasets"),
  uiOutput("vars"),
  htmlOutput("out")
)

server = function(input, output, session) {

  output$vars <- renderUI({
    req(input$d)
    selectizeInput("v",choices=names(get(input$d)), label="Variables",
                   options=list(onInitialize=I('function() {this.setValue("");}')))
  })

  output$out <- renderUI({
    req(input$d,input$v)
    HTML(paste0("The max is ",max(get(input$d)[[input$v]])))
  })

}
runApp(list(ui = ui, server = server))

启动时,选择mpg,并显示最大值。

现在,在选择了mpg之后,如果你切换到虹膜,你将得到一个几乎没有明显的错误,然后它会纠正自己。这是一个玩具示例,因此错误无关紧要,但很容易出现错误更严重的情况(就像我正在开发的应用程序一样)。

有没有办法处理嵌套的selectizeInputs,以便上游selectizeInput中的更改在更改时不会使用旧值的下游选择性输入进行评估?

由于

编辑:这个问题对模块的影响比我认为的更多:

library(shiny)
library(DT)

testModUI <- function(id) {
  ns <- NS(id)
  DT::dataTableOutput(ns("out"))
}

testMod <- function(input, output, session, data) {
  output$out <- DT::renderDataTable({
    data()
  },caption="IN MODULE")
}

ui =fluidPage(
  selectizeInput('d',choices=c('mtcars','iris'),
                 label="Datasets"),
  uiOutput("vars"),
  testModUI("test"),
  DT::dataTableOutput("test2")
)

server = function(input, output, session) {

  output$vars <- renderUI({
    req(input$d)
    selectizeInput("v",choices=names(get(input$d)), label="Variables",
                   options=list(onInitialize=I('function() {this.setValue("");}')))
  })

  observe({
    req(input$d,input$v)#,get(input$d)[[input$v]])
    validate(
      need(input$v %in% names(get(input$d)), 'Wait.')
    )
    callModule(testMod,"test",reactive(data.frame(v1=max(get(input$d)[[input$v]]))))
  })

  output$test2 <- DT::renderDataTable({
    req(input$d,input$v)#,get(input$d)[[input$v]])
    validate(
      need(input$v %in% names(get(input$d)), 'Wait.')
    )
    data.frame(v1=max(get(input$d)[[input$v]]))
  },caption="OUTSIDE MODULE")

}
runApp(list(ui = ui, server = server))

1 个答案:

答案 0 :(得分:1)

您好,您可以设置条件来检查您的代码是否会运行,在这里您只需要input$v成为input$d的有效变量,所以:

output$out <- renderUI({
  req(input$d,input$v)
  if (input$v %in% names(get(input$d))) {
    HTML(paste0("The max is ",max(get(input$d)[[input$v]])))
  }
})

# or
output$out <- renderUI({
  req(input$d,input$v)
  validate(
    need(input$v %in% names(get(input$d)), 'Wait.')
  )
  HTML(paste0("The max is ",max(get(input$d)[[input$v]])))
})
使用模块

编辑,您可以使用表达式定义模块以进行验证,如下所示:

testMod <- function(input, output, session, data, validExpr) {
  output$out <- DT::renderDataTable({
    validate(need(validExpr(), FALSE))
    data()
  },caption="IN MODULE")
}

使用函数中的表达式调用服务器中的模块:

observe({
  req(input$d,input$v)
  callModule(
    module = testMod,
    id = "test",
    data = reactive({ data.frame(v1=max(get(input$d)[[input$v]])) }), 
    validExpr = function() input$v %in% names(get(input$d))
  )
})