3

I am trying to optimize the UX for my end user in a time tracking app. Essentially it pulls in data from google calendar's api, arranges it in a tibble, and let's the user select/deselect/edit meetings, and assign them to projects. The projects are selected in a dropdown menu that I used selectizeInput to build, but am getting something similar to selectInput

I want to use a shiny::selectizeInput within a DT::datatable in Shiny. I can get the drop down to work. However, I am losing the search function that comes with selectize input. In my toy example the top selectizeInput you can click and type in the options you are looking for. The one within the datatable, you can still kind of do that, but with complicated names it would be better for the UX if you can see what you were typing.

I found this issue in the github repository, where the maker of the DT package said something like this may not be possible. However, it is 3 years old, maybe someone has figured out a work around. https://github.com/rstudio/DT/issues/390

I have also tried moving to a different ui type, tuicalendr, which for my purposes works great, but am running into the same issue. My experience in JS is limited, so I have trouble customizing JS within Shiny.

library(shiny)
library(DT)

ui <- fluidPage(
  selectizeInput("input", 
                 label = "",
                 choices = letters[1:26],
                 selected = letters[1]),
DTOutput("datatable")
)


server <- function(input, output) {

output$datatable<- renderDataTable({
  DT::datatable(data.frame(a = as.character(selectizeInput("dtinput",
                                label = "",
                                choices = letters[1:26],
                                selected = letters[1]),
             stringsAsFactors = F)),
             escape = F)
})


}

# Run the application 
shinyApp(ui = ui, server = server)

I am open to other approaches, the ideal would to be to have the data displayed in a calendar view with a checkbox and dropdown menu just below the title. But if I could solve this problem I think I could adapt the code to a calendar myself.

NotThatKindODr
  • 729
  • 4
  • 14

1 Answers1

4

One has to add the javascript functionality manually. The corresponding code would be: $('#ID').selectize().

In order to get the required html code to add, you can run: withTags(selectInput(inputId = "mselect", label = "multi", choices = letters[1:3], multiple = TRUE)). You can extract the required html part from there.

In the docu you will find that you can handover javascript code with JS(): the character options wrapped in JS() will be treated as literal JavaScript code instead of normal character strings.

You want to add the javascript code after the select part is rendered. This is assured by using the initcomplete option.

In order to use values from the input, you have to bind the inputs to shiny:

preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')

As Remko mentioned his linked post is very helpful. Almost all this info is actually available in the post. It might require some experience in shiny to create a reproducible example, so i added one for you:

Reproducible example:

library(shiny)
library(DT)

ui <- fluidPage(

  selectizeInput(
    inputId = "input",
    label = "",
    choices = letters[1:26],
    selected = letters[1]
  ),

  fluidRow(
    DTOutput(outputId = "table")
  )

)

#withTags(selectInput(inputId = "mselect", label = "multi", choices = letters[1:3], 
#    multiple = TRUE))
df <- data.frame(mselect = 
  '<select id="mselect" class="form-control" multiple="multiple">
     <option value="car">car</option>
     <option value="cars">cars</option>
     <option value="dog">dog</option>
  </select>'  
)


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

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

  observe({
    print(input$mselect)
  })

  output$table <- renderDT({

    datatable(
      data = df,
      escape = FALSE,
      options = 
        list(
          initComplete = JS(js),
          preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
          drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
      )
    )

  })

}

shinyApp(ui = ui, server = server)
Tonio Liebrand
  • 17,189
  • 4
  • 39
  • 59
  • I can't thank you enough!! Do you know where there is a good source for me to learn more about this side of shiny? If you don't have one at the ready I am sure I can find one myself. – NotThatKindODr Jun 06 '20 at 22:55
  • 1
    thats a good question. I guess it is a mixture of things. In this case you might be interested in learning some examples how to use datatables with javascript. Then it is important to understand that the user interface is basically a html page: https://shiny.rstudio.com/articles/html-tags.html. Hint: enter your `ui` variable in the console. The more of that stuff you learn the easier it gets ;) – Tonio Liebrand Jun 07 '20 at 05:54
  • This enables the user to type in a new value, but doesn't record or read that value. So, it won't work. – Rafael Cardoso Oct 20 '22 at 20:23