Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example: Excel download through context menu (not csv but xlsx) #291

Open
daeyoonlee opened this issue Nov 17, 2022 · 2 comments
Open

Example: Excel download through context menu (not csv but xlsx) #291

daeyoonlee opened this issue Nov 17, 2022 · 2 comments

Comments

@daeyoonlee
Copy link

I wanted to share the method I use for downloading reactable to excel.
Right-click on the table to bring up the context menu.

image

shiny app

library(shiny)
library(reactable)

ui <- fluidPage(
  tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.15.6/xlsx.mini.min.js"), # excel export library
  includeScript(path = "app.js"),
  includeCSS(path = "app.css"),
  reactableOutput("test")
)

server <- function(input, output, session) {
  output$test <- renderReactable(
    reactable(
      data = iris
    )
  )
}

shinyApp(ui, server)

app.js

document.addEventListener("contextmenu", function (event) {
  try {
    if (event.target.closest(".reactable") != null) {
      event.preventDefault();
      let id = event.target.closest(".reactable").id;
      let menu = document.createElement("div");
      menu.classList.add("context_menu");
      menu.style = `top:${event.pageY-5-window.pageYOffset}px;left:${event.pageX-5-window.pageXOffset}px`;
      menu.onmouseleave = function() { menu.outerHTML = ''; };
      menu.innerHTML = ("<div onclick ='JS_reactable_excel_download(\"" + id + "\")'>Excel Download</div>");
      document.body.appendChild(menu);
    }
  } catch {};
},false);

function JS_reactable_excel_download(id) {
  var json = Reactable.getInstance(id).preGroupedRows.map(row => row.original);
  for (let row = 0; row < json.length; row++) {
      for (key of Object.keys(json[row])) {
        try { 
          json[row][key] = json[row][key].replace(/<\/?[^>]+>/gi, ''); // Remove html tag if included
        } catch {};
      }
  }
  var ws = XLSX.utils.json_to_sheet(json);
  var wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
  XLSX.writeFile(wb, id+'.xlsx'); 
}

css

.context_menu {
  position: fixed;
  background: #fff;
  color: #333;
  cursor: pointer;
  padding: 5px 0px;
  border: 1px solid #ccc;
  box-shadow: rgba(0, 0, 0, 0.5) 2.4px 2.4px 3.2px;
  z-index: 111;
}

.context_menu > div {
  padding: 4px 20px;
  margin: 0;
  font-size: 12px;
}

.context_menu > div:hover {
  background: #edeeee;
}
@daeyoonlee daeyoonlee changed the title [example] Excel download through context menu Example : Excel download through context menu Nov 17, 2022
@daeyoonlee daeyoonlee changed the title Example : Excel download through context menu Example: Excel download through context menu Nov 17, 2022
@daeyoonlee daeyoonlee changed the title Example: Excel download through context menu Example: Excel download through context menu (not csv but xlsx) Dec 1, 2022
@glin
Copy link
Owner

glin commented Dec 18, 2022

That's pretty cool, thanks for sharing! I didn't know about the xlsx library (or really SheetJS). It looks like a lightweight library for creating XLSX files which would definitely be useful to a lot of people. I might adapt a simplified version of this for an example at some point.

And also FYI, this is using some undocumented reactable APIs that may change without notice in the future. But I can see how preGroupedRows would be useful for cases like this, so that could be a publicly supported state property in the future.

@daeyoonlee
Copy link
Author

Yes. In fact, there seem to be a few more undocumented functions, but they don't seem official, so I only referred to the pregroupedrows used in your csv conversion logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants