0

I wish to remove the all/none checkbox from a Reactable table used in a Shiny app. For a regular R script, an answer was suggested here.

However this solution fails with:

Warning in renderWidget(instance) : Ignoring prepended content; prependContent can't be used in a Shiny render call

The code below fails to remove the checkbox with the error mentioned above. So, how do I remove the all/none checkbox of a Reactable table in a Shiny app.

library(reactable)
library(htmlwidgets)

javascript <- JS('
document.querySelector(\'.rt-select-input[aria-label="Select all rows"]\').parentElement.parentElement.style.display="none";
')


ui <- fluidPage(reactableOutput("table")
)

server <- function(input, output, session) {
  output$table <- renderReactable({
    e <- reactable(iris,
              onClick = "select",
              selection = "multiple") 
    (p <- prependContent(e, onStaticRenderComplete(javascript)))
    })
}  
shinyApp(ui, server)  
ixodid
  • 2,180
  • 1
  • 19
  • 46

1 Answers1

1

This can be achieved by a sneaky workaround using shiny's javascript events and the shinyjs package.

  • js.code defining the js function that'll add an event handler to the shiny:visualchange event.
  • useShinyjs() use the shinyjs package.
  • extendShinyjs defining the js function in order to be used.
  • js$hideSelectAll("table") add the event handler to the table.
  • delay(100, runjs('$( "#table" ).trigger( "shiny:visualchange" );')) delay the call to the event handler in order to allow for the table to refresh.

NOTE :

I tried the shiny:value event but it didn't work it supposedly should've been executed whenever the output component is rendered but sadly it didn't.

library(reactable)
library(shiny)
library(shinyjs)
# you'll need to pass the id that you provided to reactableOutput(id)
js.code <- '
shinyjs.hideSelectAll = function(id){
    $("#"+id).on("shiny:visualchange", function({currentTarget}) {   
        currentTarget = currentTarget.querySelector(".rt-select-input[aria-label=\'Select all rows\']")
        if(currentTarget) currentTarget.parentElement.parentElement.style.display="none";
    });
} 
'

ui <- fluidPage(reactableOutput("table"),
    useShinyjs(debug=TRUE),
    extendShinyjs(text = js.code, functions = c("hideSelectAll"))
)

server <- function(input, output, session) { 
  output$table <- renderReactable({ 
    reactable(iris,
              onClick = "select",
              selection = "multiple")
    })
    js$hideSelectAll("table")
    delay(100, runjs('$( "#table" ).trigger( "shiny:visualchange" );'))
    
    #runjs('$( "#table" ).trigger( "shiny:visualchange" );')
}  
shinyApp(ui, server)  

If you're going to use it one time

library(reactable)
library(shiny)
library(shinyjs)
js.code <- '
document.querySelector(\'.rt-select-input[aria-label="Select all rows"]\').parentElement.parentElement.style.display="none";
'

ui <- fluidPage(reactableOutput("table"),
    useShinyjs(debug=TRUE)
)

server <- function(input, output, session) { 
  output$table <- renderReactable({ 
    reactable(iris,
              onClick = "select",
              selection = "multiple")
    })
    delay(100, runjs(js.code))
    
}  
shinyApp(ui, server) 

Using only shiny with no external dependency:

Even refreshing the data doesn't show the select all button. it appears that my first code isn't optimal :( but I'm leaving it as a reference.


ui <- fluidPage(reactableOutput("table"),
    actionButton("button", "refresh"),
    tags$head(tags$script(HTML('
            setTimeout(()=>{
                document.querySelector(\'#table .rt-select-input[aria-label="Select all rows"]\').parentElement.parentElement.style.display="none";
            }, 200)
    ')))
)

server <- function(input, output, session) { 
  output$table <- renderReactable({ 
    reactable(iris,
              onClick = "select",
              selection = "multiple")
    })
    observeEvent(input$button, {
    output$table <- renderReactable({ 
    reactable(mtcars,
              onClick = "select",
              selection = "multiple")
        })
    })
}  
shinyApp(ui, server)  
Abdessabour Mtk
  • 3,895
  • 2
  • 14
  • 21
  • Thank-you. I'm trying your, "If you're going to use it one time" code and it works nicely. you imply that your, "Using only shiny with no external dependency:" code is preferred. Is that accurate and if so why? – ixodid Sep 21 '20 at 03:23
  • I see that the header of the table loads and then moves left when the all/none box is removed. Is it possible to remove the box before the table loads? – ixodid Sep 21 '20 at 03:39
  • @ixodid it's better just because of the fact that there is no external dependency. if the table loads faster all you need to do is change `200`ms to another value like `125` in the [`setTimeout(()=>{......}, time_to_wait_in_ms)`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) – Abdessabour Mtk Sep 21 '20 at 05:59
  • I've noticed that the removal of the all/none checkbox misaligns the column headings. I wonder whether making it invisible and disabled is a better approach? See: https://stackoverflow.com/questions/64001820/hide-and-disable-all-none-checkbox-from-reactable-table-and-maintain-column-alig – ixodid Sep 22 '20 at 01:19