I have a R shiny application where I want to right-click on any row and show a context menu with different actionable items (printing the data of the right-clicked row).
On the first launch of the application, the context menu and the actionable items are working fine. However after clicking on the button "Update table" (which, in this reproductible example, simply update/re-render the datatable), the context menu still appears on right-click but the different actionable items are failing to work where it only shows "undefined" instead of the actual row data.
Is there anyone who could explain why the behavior of the actionable items in the JS() callback function does not work after re-rendering the datatable?
I've read a lot about the datatables' IDs being overwritten after re-rendering the output and perhaps the callback function fails to correctly point to that newly created ID (via the parameter 'selector: '#mytable tr'. I am not sure but if that is the reason, I was still unable to find a workaround.
Below is the fully reproductible example:
library(shiny)
library(DT)
c1 <- c(
"$.contextMenu({",
"selector: '#mytable tr',",
"trigger: 'right',",
"callback: function(key, options) {",
"var row = table.row(options.$trigger);",
"var data = row.data();",
"var m = 'clicked: ' + key + ' ' + data;",
"var newtab = window.open('','anotherWindow', 'width=750,height=600');",
"newtab.document.write('<p> Below is the row data! </p>', '<br>',data);",
"},",
"items: {",
"'showdata': {name:'Show row data', icon: 'fa-regular fa-folder'},",
"'showsamedata': {name:'Show same row data again', icon: 'fa-regular fa-folder'}",
"}",
"})"
)
ui <- fluidPage(
tags$head(
tags$link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.contextMenu.min.css"),tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.contextMenu.min.js"),tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.ui.position.js"),tags$script(src="https://kit.fontawesome.com/293ef49cbe.js")
),
DTOutput("mytable"),
actionButton(inputId = "update",
width = "150px",
#style = "height:35px;border:3px;border-style:double;border-color:black;",
label = div(style="vertical-align:middle;font-weight:bold","Update table"))
)
server <- function(input, output) {
#initial rendering
output$mytable <- renderDataTable({
datatable(iris, callback = JS(c1))
})
#re-rendering
observeEvent(input$update, {
output$mytable <- renderDataTable({
datatable(iris, callback = JS(c1))
})
})
}
shinyApp(ui, server)
On the first launch of the app and trying the context menu
After re-rendering the table by clicking on the button and trying the context menu
I tried to use proxyDataTables and also to use drawCallback function but no success. Also, my application needs to be able to use the callback function without the need of proxys because the actual app recreates the whole datatable through a function with many filters and then ultimately gets rendered.
I would have expected the callback function to fully work even after an update/re-rendering of the datatable.
I don't know why this beahvior. It works like this, without callback:
library(shiny)
library(DT)
c1 <- c(
"$(document).ready(function() {",
" $.contextMenu({",
" selector: '#mytable tr',",
" trigger: 'right',",
" callback: function(key, options) {",
" var tbl = $('#mytable').find('table').DataTable();",
" var row = tbl.row(options.$trigger);",
" var data = row.data();",
" var m = 'clicked: ' + key + ' ' + data;",
" var newtab = window.open('','anotherWindow', 'width=750,height=600');",
" newtab.document.write('<p> Below is the row data! </p>', '<br>',data);",
" },",
" items: {",
" 'showdata': {name:'Show row data', icon: 'fa-regular fa-folder'},",
" 'showsamedata': {name:'Show same row data again', icon: 'fa-regular fa-folder'}",
" }",
" });",
"});"
)
js <- paste0(c1, collapse = "\n")
ui <- fluidPage(
tags$head(
tags$link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.contextMenu.min.css"),tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.contextMenu.min.js"),tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.ui.position.js"),
tags$script(src="https://kit.fontawesome.com/293ef49cbe.js"),
tags$script(HTML(js))
),
DTOutput("mytable"),
actionButton(
inputId = "update",
width = "150px",
#style = "height:35px;border:3px;border-style:double;border-color:black;",
label = div(style="vertical-align:middle;font-weight:bold","Update table")
)
)
server <- function(input, output) {
#initial rendering
output$mytable <- renderDataTable({
datatable(iris)
})
#re-rendering
observeEvent(input$update, {
output$mytable <- renderDataTable({
datatable(iris)
})
})
}
shinyApp(ui, server)