简体   繁体   中英

Shiny - renderDataTable - bSearchable vs checkboxInput

I´m having problems combining two features while building a data table:

  1. I use “bSearchable” to select 1 column that I want to use the search tool to filter
  2. I use "checkboxInput" to select the columns the user wants to see.

Both work separately, but not together. If I uncheck a column in my menu input, the data disappears - like applying a filter and no data was found. How can I fix this?

          library(shiny)    
runApp(list(ui=(fluidPage(
      pageWithSidebar(
        headerPanel('Title'),
        sidebarPanel(
          helpText('Text about the table'),

          checkboxInput('columns','I want to select the columns' , value = FALSE),

          conditionalPanel(
            condition= "input.columns == true",
            checkboxGroupInput('show_vars', 'Select the columns that you want to see:', names(iris[1:4]),
                               selected =  names(iris[1:4]))
          ),

          downloadButton('downloadData', 'Download'),width = 3

        ),
        mainPanel(
          tags$head(tags$style("tfoot {display: table-header-group;}")),
          dataTableOutput("mytable1"),width = 9

        )
      ))
    )

    ,

    server=(function(input, output) {

      library(ggplot2) 
      library(XLConnect)  

      #DATA 
      tabel<- reactive({
        iris[,c(input$show_vars,"Species"), drop = FALSE]

      })

      #   OUTPUT   
      output$mytable1 = renderDataTable({
        tabel()}, 
        options = list(    
          aoColumns = list(list(bSearchable = FALSE), list(bSearchable = FALSE),list(bSearchable = FALSE),
                           list(bSearchable = FALSE),list(bSearchable = TRUE)),
          bFilter=1, bSortClasses = 1,aLengthMenu = list(c(10,25,50, -1), list('10','25', '50', 'Todas')),iDisplayLength = 10
        )

      )

      output$downloadData <- downloadHandler(
        filename = function() { paste('tabela_PSU','.xlsx', sep='') },
        content = function(file){
          fname <- paste(file,"xlsx",sep=".")
          wb <- loadWorkbook(fname, create = TRUE)
          createSheet(wb, name = "Sheet1")
          writeWorksheet(wb, tabel(), sheet = "Sheet1") 
          saveWorkbook(wb)
          file.rename(fname,file)
        },
      )


    })
    ))

The problem is by filtering the data iris based on input$show_vars , you are changing the number of columns of the DataTable. However, you have defined a fixed aoColumns option, which implies your DataTable has five columns (four non-searchable, one searchable).

Therefore, when you deselect any checkbox inputs, the filtered data doesn't match the specified options. As a result, nothing is displayed.

That is, although your data in the DataTable is reactive , the options, however, are NOT reactive .

If you read the renderDataTable 's document carefully, you will see that you can pass two types of variables to the options argument:

options A list of initialization options to be passed to DataTables, or a function to return such a list.

The differences are:

  • If you specify options as a list, Shiny assumes that the options are fixed; But since you are dynamically filtering the data based on input$show_vars , you should dynamically change the options for aoColumns as well.
  • If you pass a function as an argument for options , Shiny will know that the options are also reactive. Hence Shiny will also update the options when the data (in your case, the data.frame encapsulated in the reactive variable named tabel ) updates.

You may already know that reactive variables are themselves functions . They are evaluated in a reactive environment and when evaluated, they return the current state/value of the data. This is why you pass tabel() instead of tabel to renderDataTable .

The solution then, is to wrap the entire options list into a reactive variable (hence a function as well). Specifically, we want to dynmaically set the aoColumns option so that the number of bSearchable toggles matches the number of columns shown in the DataTable.

Below I only show the updated server part, since there's nothing needs to be changed in the UI part.

server.R

shinyServer(function(input, output) {

  library(ggplot2) 
  library(XLConnect)  

  #DATA 
  tabel<- reactive({
    iris[,c(input$show_vars,"Species"), drop = FALSE]

  })

  # wrap the `options` into a reactive variable (hence a function) so that it will
  # be evaluated dynamically when the data changes as well. 
  # `dt_options` is reactive in the sense that it will reflect the number of rows
  # visible based on the checkboxInput selections.

  dt_options <- reactive({
    # dynamically create options for `aoColumns` depending on how many columns are selected.
    toggles <- lapply(1:length(input$show_vars), function(x) list(bSearchable = F))
    # for `species` columns
    toggles[[length(toggles) + 1]] <- list(bSearchable = T)

    list(
      aoColumns = toggles,
      bFilter = 1, bSortClasses = 1, 
      aLengthMenu = list(c(10,25,50, -1), list('10','25', '50', 'Todas')),
      iDisplayLength = 10
      )
  })

  #   OUTPUT
  output$mytable1 = renderDataTable({
    tabel()}, 
    options = dt_options
  )

  output$downloadData <- downloadHandler(
    filename = function() { paste('tabela_PSU','.xlsx', sep='') },
    content = function(file){
      fname <- paste(file,"xlsx",sep=".")
      wb <- loadWorkbook(fname, create = TRUE)
      createSheet(wb, name = "Sheet1")
      writeWorksheet(wb, tabel(), sheet = "Sheet1") 
      saveWorkbook(wb)
      file.rename(fname,file)
    },
  )

})

(Note that I separate the UI part and server part into ui.R and server.R .)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM