2

I make making a Shiny app in R that shows the user an Excel-like grid. The excelR package is a wrapper for a JS package JSpreadsheet. This package automatically puts row numbers in the left-most column. I do not want them.

By digging into the JavaScript, I was finally able to figure out how to use an actionButton to remove the row numbers by sending a JS command:

library(shiny)
library(excelR)
library(shinyjs)

jsCode <- "shinyjs.hideindex = function(params) {document.getElementById('table').jexcel.hideIndex();}"

ui <- fluidPage(
  useShinyjs(),
  extendShinyjs(text = jsCode, functions = "hideindex"),
  excelOutput("table", height = 175),
  actionButton('hide_button', 'Hide Index Column')
)

server <- function(input, output, session){
  output$table <- renderExcel({
    excelTable(data = head(iris),
               columns = data.frame(title = names(iris),
                                    type = c('numeric', 'numeric', 'numeric', 'numeric', 'text')))
    })

  onclick("hide_button", js$hideindex())

}

shinyApp(ui, server)

But I would really like to have the table render automatically without the index column (row numbers). I tried to use observeEvents (and many, many other things) that watched for changes in input$table, but the input does not seem to get created until the table is edited.

Michael Dewar
  • 2,553
  • 1
  • 6
  • 22

1 Answers1

1

I modified your example to make it more discrete, however it will run every time someone modify your app (because of the observe() function).

library(shiny)
library(excelR)
library(shinyjs)

jsCode <- "shinyjs.hideindex = function(params) {document.getElementById('table').jexcel.hideIndex();}"

ui <- fluidPage(
  useShinyjs(),
  extendShinyjs(text = jsCode, functions = "hideindex"),
  excelOutput("table", height = 175),
  hidden(actionButton('hide_button', 'Hide Index Column')) # Hide from start 
)

server <- function(input, output, session){
  output$table <- renderExcel({
    excelTable(data = head(iris),
               columns = data.frame(title = names(iris),
                                    type = c('numeric', 'numeric', 'numeric', 'numeric', 'text')))
  })
  
  observe({ # Automatic click on it even if hidden
    click("hide_button")
  })
  onclick("hide_button", js$hideindex())  
}

shinyApp(ui, server)

It could be better to run this only at app start but I didn't solve it yet.

Gowachin
  • 1,251
  • 2
  • 9
  • 17
  • I did add a reactiveValue that turn to FALSE after first click and limit the number of click happening after, but I would like to remove all the observe part and button if possible. – Gowachin Mar 07 '22 at 10:43
  • 1
    Thanks, this is very interesting. If you move the `click("hide_button")` inside the `renderExcel` then index column will get re-hidden when the table rerenders because of its own reactivity. This also gets rid of that observer. Sometimes there is a brief flicker when the table re-renders. (Add an `actionButton("reload", "reload)` to the ui and `input$reload` inside the `renderExcel` to force it.). Do you have any idea how to remove the flicker? – Michael Dewar Mar 08 '22 at 00:23
  • 1
    I've used this in my project already and it works well. Thanks a lot! – Michael Dewar Mar 08 '22 at 07:16
  • I guess the flicker is caused by the time between the rendering and the `onclick()` call which are re-evaluated each time there is a modification and thus a call of the server function. My bet is that we could reduce this by calling the javascrip as close as we can from the rendering, but I didn't managed to do this. The minimal example don't have this. – Gowachin Mar 08 '22 at 08:26
  • 1
    I was able to reduce the flicker a great amount (often don't see it at all) by using 'on.exit' to trigger the click from inside the render function. Thanks a lot for this answer! It really helps me out! – Michael Dewar Mar 08 '22 at 11:47