Disabling selectizeInput in second page of datatable in RShiny

I have a datatable, in which I have embedded selectizeInputs. I have used jquery to enable some options in the selectizeInputs (like creation options).

Now, due to a business use case I would like to disable some selectizeInputs (dynamically selected, through some condition). These inputs could be on the 2nd, 3rd,.. nth page of the datatable as well.

However, I am only able to disable the inputs on the 1st page and not on the subsequent pages. I am attaching a minimal and reproducible example, it would be great if someone could help me out.

library(shiny)
library(DT)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  selectizeInput(
    inputId = "input",
    label = "",
    choices = letters[1:26],
    selected = letters[1]
  ),
  
  fluidRow(
    DTOutput(outputId = "table"),
    tags$script(HTML("Shiny.addCustomMessageHandler('unbind-DT', function(id) {
                                       Shiny.unbindAll($('#'+id).find('table').DataTable().table().node());
                                     })"))
  )
  
)

df <- data.frame('a' = c(1,2), 'sel_input' = NA)
df[1,'sel_input'] <- as.character(
  selectizeInput(inputId = 'mselect', choices=c('car','cars','dog'),
                 label=NULL, selected=NULL))
df[2,'sel_input'] <- as.character(
  selectizeInput(inputId = 'nselect', choices=c('lambo','audi','merc'),
                 label=NULL, selected=NULL))


js <- c(
  "function(){Shiny.bindAll(this.api().table().node());",
  "  $('#mselect').selectize({
                           delimiter: \',\',
                           persist: false,
                           create: function(input) {
                              return {
                                 value: input,
                                 text: input
                              }
                           }
                            });",
  "$('#nselect').selectize({
                           delimiter: \',\',
                           persist: false,
                           create: function(input) {
                              return {
                                 value: input,
                                 text: input
                              }
                           }
                            });",
  #"$('#mselect')[0].selectize.enable()",
  #"$('#nselect')[0].selectize.disable()",
  "}"
)

server <- function(input, output, session) {
  
  observe({
    print(input$mselect)
  })
  session$sendCustomMessage('unbind-DT', 'table')
  output$table <- renderDT({
    datatable(
      data = df,
      escape = FALSE,
      options = list(
        dom='tp',
        pageLength=1,
        processing=F,
        preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
        drawCallback = JS(js)
      )
    )
    
  })
  
}

shinyApp(ui = ui, server = server)

What do you want to be there instead of the select input when it is disabled?

I expect there are relatively fewer forum users that can help you given that it seems to be a predominantly javascript question...

So, I was able to resolve it on my own. Basically the problem here is not R/Rshiny based. It is actually a javascript bug in the code that I was overlooking.

When you do pagination, the elements only in the current (selected) page are a part of the DOM. All others are removed/not created. In the code above, in the drawCallback (this is the piece of code that runs every time the datatable needs to be re-rendered) I am issuing commands for all the elements, irrespective if they are present in the DOM or not. Because of this the javascript code fails and the disabling/enabling does not happen.

The solution here is to first check if an element is active in the DOM or not and only then issue enabling/disabling command.

So, in essence, enclose the above commands in a if else statement.

if ($('#mselect').length > 0){
$('#mselect').selectize()[0].selectize.enable();
}

if ($('#nselect').length > 0){
$('#nselect').selectize()[0].selectize.disable();
}

This way the javascript code will only run when that specific element exists in the DOM and then you would be able to implement disabling selectInput in second page of paginated datatable.

Hope it helps someone else as well.

Cheers!

1 Like