-
Notifications
You must be signed in to change notification settings - Fork 79
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
Dynamically styling table in shiny without re-rendering #255
Comments
Hi, just so I understand, the table needs to be conditionally styled based on some changing data in the Shiny app, and the table data never changes? If so, that's an interesting question, and I can't think of a great way to do this today. That conditionally styling rule will probably have to be part of the table or column options (e.g., a custom row style function), but there's no way to change either the table row style or the column definitions of an existing table today. Maybe a future enhancement to I've also been thinking about an unrelated feature to attach arbitrary metadata to a table for custom rendering/styling purposes, that doesn't have to go in the table data. That might be even easier to use. For example, the JavaScript API could provide a way to access that custom data like While typing this up, I remembered that you can actually use a hidden column in the data to store arbitrary metadata for custom rendering/styling, and it's used pretty commonly today but just kind of hacky. An example would be the Show data from other columns example. This data can be updated using But here's a quick implementation of the "arbitrary metadata" idea using a hidden column. This Shiny app has a library(shiny)
library(reactable)
data <- MASS::Cars93[1:10, c("Manufacturer", "Model", "Type", "Price")]
# Add a hidden column for arbitrary metadata, filled with empty lists/objects
data$.meta <- list(list())
ui <- fluidPage(
verbatimTextOutput("highlightedValue"),
reactableOutput("table")
)
server <- function(input, output, session) {
rv <- reactiveValues(highlightedValue = NA)
observe({
# Set highlighted value to a new random value from the Price column every second
invalidateLater(1000, session)
rv$highlightedValue <- sample(data$Price, 1)
# Update the metadata column with the new highlighted value.
# We don't need to fill the entire column, so just use the first row.
data$.meta[[1]] <- list(highlightedValue = rv$highlightedValue)
updateReactable("table", data = data)
})
output$highlightedValue <- renderPrint({
reactiveValuesToList(rv)
})
output$table <- renderReactable({
reactable(
data,
columns = list(
# Hide the metadata column
.meta = colDef(show = FALSE)
),
# Style rows based on the highlighted value from the table metadata
rowStyle = JS("(rowInfo, state) => {
const meta = state.data[0]['.meta']
if (rowInfo.values['Price'] === meta.highlightedValue) {
return { backgroundColor: 'orange' }
}
}")
)
})
}
shinyApp(ui, server) |
Hello, Thank you for your response. re the clarification in your post.
The data changes every few seconds. The change can be to any column to the dataframe (except column B) but for the purpose of simplicity I am updating the entire table. The way datatables have been conceived, I believe is to render large amounts of static data for analysis purposes. However there are multiple use cases where all the data in the table can be dynamic (think about state monitoring of multiple devices). I do not think there are elegant solutions in the R universe yet which allow for this to be implemented. I have been able to implement this with a hacky solution of using a hidden column and styling the row with css. The hidden column can have boolean or integer data which can be used as a selector for styling a particular row. So for now it works, but as you have mentioned the solution is hacky. It'll be nice to have a JS based approach where any cell/column/row can be styled based on either the cell value or whenever a cell/row value changes where the JS is evaluated. I'm glad you've added this as an enhancement. Look forward to a nice solution. Regards |
Custom metadata is now a built-in feature in latest development version:
The hacky hidden column won't be necessary anymore with this, and you can simplify the app a bit: library(shiny)
library(reactable)
data <- MASS::Cars93[1:10, c("Manufacturer", "Model", "Type", "Price")]
ui <- fluidPage(
verbatimTextOutput("highlightedValue"),
reactableOutput("table")
)
server <- function(input, output, session) {
rv <- reactiveValues(highlightedValue = NA)
observe({
# Set highlighted value to a new random value from the Price column every second
invalidateLater(1000, session)
rv$highlightedValue <- sample(data$Price, 1)
updateReactable("table", meta = list(highlightedValue = rv$highlightedValue))
})
output$highlightedValue <- renderPrint({
reactiveValuesToList(rv)
})
output$table <- renderReactable({
reactable(
data,
# Style rows based on the highlighted value from the table metadata
rowStyle = JS("(rowInfo, state) => {
if (rowInfo.values['Price'] === state.meta.highlightedValue) {
return { backgroundColor: 'orange' }
}
}"),
meta = list(highlightedValue = NULL)
)
})
}
shinyApp(ui, server) Also, thanks for the context on the dynamically changing data. |
cheers, great work. thank you. |
Hello,
Thank you for this excellent suite of tools. I'm struggling with dynamic row highlighting, so I thought I might post a question here.
I have a shiny application which updates in real time a table and a value based on which the table elements are computed.
e.g.
Value: 8235
Table:
Here the value updates in real time and the row that is highlighted is equal to the value of Column B rounded to the nearest 100.
Is there a way that the row styling can be updated as the value changes through time (e.g. if the value changes to 8300, the third row should be highlighted) - without the need for re-rendering the table as that is expensive. I believe this should be possible with client side (browser side) JS execution, but I'm unable to figure out how to implement it.
Any pointer will be most appreciated.
Regards
JJ
The text was updated successfully, but these errors were encountered: