Simon.S.A.
Simon.S.A.

Reputation: 6931

data table uiOutput disappears on redraw

I am displaying widgets within a DT datatables in an R Shiny app.

Following a similar approach to here, widgets are inserted as text into the data table. Then using the option escape = FALSE, the text of the widgets is interpretated as HTML and the widget is displayed.

This approach has worked very well, until I came to redraw the datatable. On redraw the widgets within the table no longer appear. You can test with the following example. When "Redraw" is clicked, the UI output showing the text "here" disappears.

# UI
ui = fluidPage(
  actionButton("draw", "Redraw"),
  # uiOutput("ui"),
  DT::dataTableOutput("classify_table")
)

# server
server = function(input, output, session) {
  
  output$ui = renderUI({ p("here") })
  
  output$classify_table <- DT::renderDataTable({
    
    df = data.frame(
      rows = input$draw,
      UI = as.character(uiOutput("ui")),
      stringsAsFactors = FALSE
    )
    
    DT::datatable(
      df,
      escape = FALSE,
      options = list(
        dom = "t",
        preDrawCallback = DT::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
        drawCallback = DT::JS('function() { Shiny.bindAll(this.api().table().node()); } ')
      )
    )
  })
}

# run
shinyApp(ui, server)

My best hypothesis is that Shiny ends up with two uiOutput("ui") bound. This would mean it does not display at the uiOutput("ui") in the redrawn table.

Any idea what is causing this behavior and how to fix it? Even suggestions for how to better debug this behavior would be helpful.

Another possible solution is to bind the UI component to shiny directly, instead of in the callback. But I don't know how to determine the JavaScript for this.

Upvotes: 0

Views: 63

Answers (1)

Simon.S.A.
Simon.S.A.

Reputation: 6931

Based on the comment from @Stéphane Laurent, I found this answer by them (search term user:1100107 [dt] unbind).

I inserted this code into the UI

tags$script(HTML(
      "Shiny.addCustomMessageHandler('unbindDT', function(id) {
        var $table = $('#'+id).find('table');
        if($table.length > 0){
          Shiny.unbindAll($table.DataTable().table().node());
        }
      })"
  ))

and this code at the start of the DT::renderDataTable({:

session$sendCustomMessage("unbindDT", "classify_table")

Note that if working in a module, we need to wrap with ns as so:

session$sendCustomMessage("unbindDT", ns("classify_table"))

Upvotes: 1

Related Questions