rstudio / DT

R Interface to the jQuery Plug-in DataTables
https://rstudio.github.io/DT/
Other
599 stars 180 forks source link

Integrate R-interface for custom cell-rendering #990

Open markschat opened 2 years ago

markschat commented 2 years ago

First: DT is a great and mature package I love and use lot - thank´s for that 🎉

One major drawback I´ve noticed when applying custom renderings on cell content. DT has some predefined format*() functions which are useful for specific cases. If I want a different cell output (icons, badges, tooltips, ...) things get quiet uncomfortable.

Either I can use R and format the input data upfront using all the great tools like htmltools, fontawesome, ... (This feels unclean to me, as DT should be responsible for the cell formatting/ styling and not the "raw input data") or I have to go to the JavaScript side of things, which is ok but takes me outside of R.

Recently I took a look at reactable and fell in love with their concept of custom cell rendering. Here´s a short example:

library(reactable)

data <- MASS::Cars93[1:5, c("Manufacturer", "Model", "AirBags")]

reactable(
  data, 
  columns = list(
    Model = colDef(cell = function(value, index) {
      url <- sprintf("https://wikipedia.org/wiki/%s_%s", data[index, "Manufacturer"], value)
      htmltools::tags$a(href = url, target = "_blank", as.character(value))
    }),
    AirBags = colDef(cell = function(value) {
      if (value == "None") "\u274c No" else "\u2714\ufe0f Yes"
    })
  )
)

At the moment DT has a very similar feature options$columnDefs$render that only supports JS-Functions. I think it would be great to expand this to regular R-Functions. It would add endless flexibility to custom cell-rendering with an clean and easy to use interface.


By filing an issue to this repo, I promise that

I understand that my issue may be closed if I don't fulfill my promises.

shrektan commented 2 years ago

Is PR #949 what you want?

markschat commented 2 years ago

Is PR #949 what you want?

@shrektan Your PR nails it! It´s nearly identical 😀 Thank´s for providing some workable code 👏. I just went through all issues to see if there is a similar request, didn´t check the PR´s.

I will give it a try later eventually and some feedback if possible. Should this issue be closed/ referenced in your PR?

mikmart commented 9 months ago

I played around with the idea of using DataTables' orthogonal data for implementing a formatCustom() in this style. A crude POC, but could possibly go somewhere.

formatCustom = function(table, columns, formatter) {
  if (attr(table$x, 'rownames')) columns = columns + 1
  table$x$data[columns] = lapply(table$x$data[columns], applyCustom, formatter)
  table$x$options$columnDefs = append(
    table$x$options$columnDefs, list(customDef(columns - 1))
  )
  table
}

applyCustom = function(x, formatter) {
  transpose(list(`_disp` = format(formatter(x)), `_orig` = x))
}

transpose = function(x) {
  purrr::list_transpose(x, simplify = FALSE)
}

customDef = function(targets) {
  list(targets = targets, render = list(display = '_disp', `_` = '_orig'))
}

DT::datatable(data.frame(foo = rnorm(10))) |>
  formatCustom(1, formattable::color_tile('yellow', 'red'))

image