【问题标题】:Conditional selection type for datatables embedded in a shiny app嵌入在闪亮应用程序中的数据表的条件选择类型
【发布时间】:2016-04-05 12:58:15
【问题描述】:

实际问题

我有一个通过DT::datatable 接口/创建并通过DT::renderDataTable 呈现的DataTable。

如何通过将DT::renderDataTable 的参数selection 的值基于shiny::radioButtons 的值来使选择类型有条件?

示例

在以下示例中,我尝试使 DT::renderDataTable 的参数 selection 的值依赖于单选按钮输入 (input$action_selectiontype)。

问题:

生成的呈现表不会反应性地反映所做的选择。似乎input$action_selectiontype 的初始值已被考虑且无法更改。

你可以通过设置全局变量DFLT_action_selectiontype来使用默认值 (single 或multiple)

全局

# Packages ----------------------------------------------------------------

library(shiny)

# Variables ----------------------------------------------------------------

DFLT_action_selectiontype <- "single"

# Functions ---------------------------------------------------------------

createRecord <- function(input, db) {
  db$data <- rbind(
    db$data,
    data.frame(
      task = input$task,
      time = input$time,
      time_unit = "hour",
      stringsAsFactors = FALSE
    )
  )
}
updateRecord <- function(input, db, selection) {
  db$data[selection,] <- data.frame(
    task = input$task,
    time = input$time,
    time_unit = "hour",
    stringsAsFactors = FALSE
  )
}
deleteRecord <- function(db, selection) {
  db$data <- db$data[-selection,]
}
niceNames <- function(x) {
  s <- strsplit(x, " |_|\\.", perl = TRUE)[[1]]
  paste(toupper(substring(s, 1,1)), substring(s, 2),
    sep = "", collapse = " ")
}

用户界面

ui <- fluidPage(
  div(
    style = "display:inline-block",
    p(),
    actionButton("action_trigger", "Create")
  ),
  tabsetPanel(
    tabPanel(
      title = "Selection options",
      p(),
      radioButtons("action_selectiontype", "Selection type",
        choices = c("single", "multiple"),
        selected = DFLT_action_selectiontype, inline = TRUE)
    )
  ),
  hr(),
  uiOutput("ui_input"),
  hr(),
  h3("Database"),
  DT::dataTableOutput("dt")
)

服务器

server <- function(input, output, session) {
  ## Initialize DB //
  db <- reactiveValues(data = data.frame(
    task = character(),
    time = numeric(),
    time_unit = character()
  )[-1,])

  ## UI control //
  ui_control <- reactiveValues(
    case = c("hide", "create", "update")[1],
    selection = NULL,
    refresh = TRUE
  )
observeEvent(input$action_trigger, {
    ui_control$case <- "create"
  })

  ## Render UI //
  output$ui_input <- renderUI({
    case <- ui_control$case
    if (case == "hide")
      return()

    ## Case dependent input //
    if (case == "create") {
      task <- ifelse(is.null(tmp <- isolate(input$task)), "", tmp)
      time <- ifelse(is.null(tmp <- isolate(input$time)), "", tmp)
      buttons <- div(
        style = "display:inline-block",
        actionButton("action_create", "Create"),
        actionButton("action_cancel", "Cancel")
      )
      updateTextInput(session, "first")
    } else if (case == "update") {
      task <- db$data[ui_control$selection, "task"]
      time <- db$data[ui_control$selection, "time"]
      buttons <- div(
        style = "display:inline-block",
        actionButton("action_update", "Update"),
        actionButton("action_cancel", "Cancel"),
        p(),
        actionButton(
          "action_delete",
          "Delete",
          icon = icon("exclamation-triangle")
        )
      )
    } else {
      stop(sprintf("Invalid case: %s", case))
    }
    tagList(
      textInput("task", "Task", task),
      numericInput("time", "Time", time),
      buttons
    )
  })

  ## CRUD operations //
  observeEvent(input$action_create, {
    createRecord(input, db = db)
    ui_control$case <- "hide"
  })
  observeEvent(input$action_update, {
    updateRecord(input, db = db, selection = ui_control$selection)
    ui_control$refresh <- NULL
    ui_control$refresh <- TRUE
    # ui_control$case <- "hide"
  })
  observeEvent(input$action_delete, {
    deleteRecord(db = db, selection = ui_control$selection)
    tmp <- ui_control$selection[1] - 1
    if (tmp == 0) tmp <- NULL
    ui_control$selection <- tmp
    ui_control$refresh <- NULL
    ui_control$refresh <- TRUE
    # ui_control$case <- "hide"
  })
  observeEvent(input$action_cancel, {
    ui_control$case <- "hide"
  })

  ## Selection //
  observe({
    idx <- input$dt_rows_selected
    ui_control$selection <- idx
  })
  observe({
    idx <- ui_control$selection
    if (!is.null(idx)) {
      ui_control$case <- "update"
    } else {
      ui_control$case <- "hide"
    }
  })

  ## Render table: preparations //
  observeEvent(input$action_selectiontype, {
    ui_control$refresh <- NULL
    ui_control$refresh <- TRUE
  })
  dt_options = reactive({
    list(
      dom = "ltipr",
      autoWidth = TRUE,
      scrollX = TRUE,
      lengthMenu = list(
        c(3, 5, -1),
        c(3, 5, "All")
      ),
      iDisplayLength = 3
    )
  })

  ## Render table: DT //
  output$dt <- DT::renderDataTable({
    if (!ui_control$refresh) {
      return()
    }
    ## Note:
    ## Not really necessary for this example use case as `db$data` already
    ## introduces a reactive dependency.
    ## However, that might not always be the case for data I/O when an
    ## actual database is involved. In this case, this part will most likely
    ## have to be informed about required re-rendering by an explicit reactive
    ## value that other parts update upon I/O operations

    tmp <- db$data
    names(tmp) <- sapply(names(tmp), niceNames)
    tmp
  }, selection = input$action_selectiontype, options = dt_options())

  ## DT proxy //
  proxy <- DT::dataTableProxy("dt")
  ## Keep/restory previous selection //
  observe({
    ui_control$refresh
    DT::selectRows(proxy, as.numeric(ui_control$selection))
  })

  ## Resets //
  observe({
    if (ui_control$case == "create") {
      updateTextInput(session, "task", value = sprintf("Test %s", Sys.time()))
      updateTextInput(session, "time", value = 1)
    }
  })
}

运行

shinyApp(ui, server)

Gist 上的参考应用

上面使用的部分也包含在我的reference app 中,它捆绑了一些与数据功能相关的东西/学习,以防您感兴趣:

shiny::runGist("https://gist.github.com/rappster/d48916fbf8e8d0456ae2")

【问题讨论】:

    标签: javascript r datatables shiny dt


    【解决方案1】:

    不是 100% 确定,但我认为选择参数仅在表格启动时使用,之后不会更新。

    您可以尝试将datatable 存储在反应式表达式中以强制更改参数。这是一个例子:

    library(shiny)
    library(DT)
    shinyApp(
      ui = fluidPage(
        radioButtons("action_selectiontype", "Selection type",
                     choices = c("single", "multiple"),
                     selected = "single", inline = TRUE),
        DT::dataTableOutput("dt")
        ),
    
      server = function(input, output) {
        table <- reactive({datatable(iris,selection=input$action_selectiontype)})
    
        output$dt <- DT::renderDataTable({
          table()})
      }
    )
    

    【讨论】:

      猜你喜欢
      • 2014-04-11
      • 2016-01-06
      • 1970-01-01
      • 1970-01-01
      • 2014-03-26
      • 2018-06-20
      • 1970-01-01
      • 2019-01-08
      相关资源
      最近更新 更多