1

In my Shiny app, I want to include a selectInput in a DT datatable and allow selection of multiple options. This renders fine with multiple = F, but with multiple = T, the selection doesn't display or work properly. Please see example below. When "Multiple" is unselected, the selectInput renders fine in the table, but when it is selected, the selectInput is not rendered properly. Any suggestions?

Update: I modified the code to include a selectInput by itself with multiple = TRUE to show what I expect it to look like in the table. Specifically, in the table, there is no field above the dropdown with the selections displayed and I am unable to select multiple choices. Also see screenshot. enter image description here

require(shiny)
require(DT)
shinyApp(
  ui = fluidPage(
    checkboxInput(inputId = "multiple", label = "Multiple", value = F),
    selectInput(inputId = "expected", label = "Expected", choices = letters, multiple = T),
    DT::dataTableOutput("mytable")
  ),
  server = function(input, output, session) {
    output$mytable <- DT::renderDataTable({
      if(is.null(input$multiple)) return()
      DT::datatable(
        data = data.frame(
          Col1 = c(
            as.character(selectInput(
              inputId = "id1", 
              label = NULL, 
              choices = letters, 
              multiple = input$multiple
            ))
          )
        ),
        escape = F,
        selection = "none"
      )
    })
  }
)

Update 2: Thanks to @Jamie for a great solution. I was able to modify that solution when I need multiple selectInputs in my table and want the same desired format. See below:

require(shiny)
require(DT)

SelectizeIDs <- function(ids) {
  myStrings <- as.character(sapply(ids, function(id) {
    paste0("  $('#", id, "').selectize();")
  }))
  c(
    "function(settings){",
      myStrings,
    "}"
  )
}

shinyApp(
  ui = fluidPage(
    checkboxInput(inputId = "multiple", label = "Multiple", value = F),
    selectInput(inputId = "expected", label = "Expected", choices = letters, multiple = T),
    DT::dataTableOutput("mytable")
  ),
  server = function(input, output, session) {
    output$mytable <- DT::renderDataTable({
      DT::datatable(
        data = data.frame(
          Col1 = c(
            as.character(selectInput(
              inputId = "id1",
              label = NULL,
              choices = letters,
              multiple = input$multiple
            )),
            as.character(selectInput(
              inputId = "id2",
              label = NULL,
              choices = letters,
              multiple = input$multiple
            ))
          )
        ),
        escape = F,
        selection = "none",
        options = list(
          ordering = F,
          initComplete = JS(SelectizeIDs(c("id1", "id2"))),
          preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
          drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
        )
      )
    })
  }
)
Ben Ernest
  • 445
  • 3
  • 14
  • 1
    I ran this and didn't see a problem. With multiple unticked, the selection box opened to show all values. When it was ticked it only showed the first four, but I was able to scroll down and select multiple options. What is your expectation? – stomper Nov 23 '22 at 19:52
  • Works as expected for me too – HubertL Nov 23 '22 at 19:53
  • @stomper I updated my code to include a selectInput by itself with multiple = T which is how I expect it to look in the table. Also included screenshot – Ben Ernest Nov 23 '22 at 20:12
  • @HubertL please see update. Does your app not look like my screenshot? – Ben Ernest Nov 23 '22 at 20:31

1 Answers1

1

Here's an option where I leaned heavily from this question.

SelectizeInput inside DT::datatable only works as html

Which leans on this question. Shiny widgets in DT Table

Since your data data.frame has the appropriate html already set up. You need to make sure that selectize is added to the id in this case id1. From inspecting element on your expected vs actual input, it looks like all the selectize JS is being excluded

js <- c(
  "function(settings){",
  "  $('#id1').selectize()",
  "}"
)

Then in the options initialize the js function above and and bind the inputs.

shinyApp(
  ui = fluidPage(
    checkboxInput(inputId = "multiple", label = "Multiple", value = F),
    selectInput(inputId = "expected", label = "Expected", choices = letters, multiple = T),
    DT::dataTableOutput("mytable")
  ),
  server = function(input, output, session) {
    output$mytable <- DT::renderDataTable({
      # if(is.null(input$multiple)) return()
      DT::datatable(
        data = data.frame(
          Col1 = c(
            as.character(selectInput(
              inputId = "id1",
              label = NULL,
              choices = letters,
              multiple = input$multiple
            ))
          )
        ),
        escape = F,
        selection = "none",
        options = list(
          initComplete = JS(js),
          preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
          drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
        )
      )
    })
  }
)

output

Jamie
  • 1,793
  • 6
  • 16
  • That does the trick! Thank you. One minor tweak is to set `ordering = F` in the options list. I clicked on the column header (accidentally) which sorted the table and noticed that it reverted back to the original (not desired) format. And one follow up question: how would I extend the "js" code snippet if I have multiple selectInputs in my table? – Ben Ernest Nov 23 '22 at 23:15
  • 1
    See update 2. I was able to extend your js snippet to selectize multiple selectInput ids. Thanks again. – Ben Ernest Nov 23 '22 at 23:33
  • Could also consider `selectInputMultiple` in from the `DTEdit` package – big_cactus Jul 25 '23 at 20:21