Open tbradley1013 opened 4 years ago
FYI - I have also posted this question on RStudio Community
Have you had any luck with this @tbradley1013 ? I have a similar issue whereby I need to control the selected rows in a reactable.
Follow these steps with the example below to see what I mean.
You will see the tick is just passed to "b" in Table 2 as the selectionId tableid2 remains a value of 1. I have tried a few ideas (commented out below) to programatically change the value of tableid2, with no luck.
Ideally I need to deselect all rows in Table 2 when any rows in Table 1 change.
library(reactable)
# reactable * 0.1.0.9000 2019-12-13 [1] Github (glin/reactable@566a4ba)
library(shiny)
library(data.table)
my_data <- data.table(col1 = letters[1:5])
ui <- shinyUI(
fluidPage(
# shinyjs::useShinyjs(),
column(4,
h5('Table 1'),
reactableOutput("test_table_react1")
),
column(4,
h5('Table 2'),
reactableOutput("test_table_react2")
)
)
)
server <- shinyServer(function(input, output, session) {
output$test_table_react1 <- renderReactable({
reactable(
data = my_data,
selection = "multiple",
selectionId = "tableid1",
onClick = "select",
defaultSelected = NULL,
fullWidth = FALSE
)
})
observeEvent(input$tableid1, {
# shinyjs::reset(id = 'tableid2')
# output$test_table_react2 <- renderReactable({NULL})
# HTML('Shiny.setInputValue("tableid2", NULL);')
print(input$tableid2)
})
output$test_table_react2 <- renderReactable({
req(input$tableid1)
reactable(
data = my_data[input$tableid1, ],
selection = "multiple",
selectionId = "tableid2",
onClick = "select",
defaultSelected = NULL,
fullWidth = FALSE
)
})
})
shinyApp(ui, server)
Hi, there isn't a way to do this in the current release version of reactable, but I've been thinking about adding something like a proxy to make this possible. In the development version on GitHub, there's a new experimental updateReactable(outputId, selected = ..., expanded = ...)
function to update the selected or expanded rows. For example:
https://glin.github.io/reactable/articles/examples.html#update-a-reactable-instance
# Requires reactable v0.1.0.9000
# devtools::install_github("glin/reactable")
library(shiny)
library(reactable)
ui <- fluidPage(
actionButton("select_btn", "Select rows"),
actionButton("clear_btn", "Clear selection"),
actionButton("expand_btn", "Expand rows"),
actionButton("collapse_btn", "Collapse rows"),
reactableOutput("tbl"),
"Rows selected:",
verbatimTextOutput("rows_selected")
)
server <- function(input, output) {
output$tbl <- renderReactable({
reactable(
iris,
selection = "multiple",
selectionId = "selection",
onClick = "select",
details = function(index) paste("Row details for row:", index)
)
})
observeEvent(input$select_btn, {
# Select rows
updateReactable("tbl", selected = c(1, 3, 5))
})
observeEvent(input$clear_btn, {
# Clear row selection using NA or integer(0)
updateReactable("tbl", selected = NA)
})
observeEvent(input$expand_btn, {
# Expand all rows
updateReactable("tbl", expanded = TRUE)
})
observeEvent(input$collapse_btn, {
# Collapse all rows
updateReactable("tbl", expanded = FALSE)
})
output$rows_selected <- renderPrint({
print(input$selection)
})
}
shinyApp(ui, server)
If you're able to try it out, let me know what you think. I'm not sure if this will be the final API yet.
Also note that you can only expand or collapse all rows for now. Expanding individual rows may be possible in the future, but it'll be complicated to implement (related: #23).
This is great! Thanks for getting back to me and implementing this!
A couple of follow-up questions based on playing with the dev version this morning:
It would be useful to be able to expand particular rows, but I can certainly work around that since I can now dynamically select rows!
Thanks again!
There wasn't, but I've added a page
argument so you can change the current page like updateReactable("mytbl", selected = 11, page = 2)
(example).
Love that idea, and I've wanted to do that for a while now as well. I thought it made sense to add a rowInfo.selected
property to the rowClass
/rowStyle
JS functions so you can set CSS classes or styles on selected rows.
For example: https://glin.github.io/reactable/articles/examples.html#style-selected-rows
# Requires reactable v0.1.0.9000
# devtools::install_github("glin/reactable")
library(reactable)
reactable( iris[1:4, ], selection = "multiple", defaultSelected = c(1, 3), rowClass = JS("function(rowInfo) { return rowInfo.selected ? 'selected' : '' }"), rowStyle = JS("function(rowInfo) { if (rowInfo.selected) { return { backgroundColor: '#eee', boxShadow: 'inset 2px 0 0 0 #ffa62d' } } }"), borderless = TRUE, onClick = "select" )
3. I think most of the internal table state can be updated programmatically, and you can find a list of the easier-to-implement ones here: https://github.com/tannerlinsley/react-table/tree/v6#fully-controlled-component. Now that `updateReactable()` exists, these will all probably be added eventually, but feel free to file a feature request if there something you need in particular :)
This is awesome! One last question to go with the updating the selected page. Is there a way to access the number of rows per page? If I restrict it to only being 10 then I can obviously figure out what page needs to be selected based on the row selected. But if I allow the user to select a page length of 10, 50, or 100 would there be any way to access which of those they have selected from the table?
My JS ability is virtually non-existent but I may take a look at the ones you have already implemented and create a PR for any of the others that I might need/want! Thanks for making this an option!
There's a way to get the page size, but it's not easily accessible right now. That would be through the rowClass
/rowStyle
callbacks like:
reactable(
iris,
showPageSizeOptions = TRUE,
rowClass = JS("function(rowInfo, state) {
console.log(state.pageSize)
// Could get it in Shiny using something like:
// Shiny.onInputChange('tbl_page_size', state.pageSize)
}")
)
One idea would be to support similar JS callbacks in updateReactable()
:
updateReactable("tbl", page = JS("function(state) {
// Calculate what page to go to based on state.pageSize
}"))
Another idea would be to add something like a getReactableInfo(outputId)
function, where you can access a reactable instance's state directly in R and Shiny:
getReactableInfo("tbl")
# list(
# pageSize = 20,
# page = 2,
# pages = 8,
# selected = c(3, 4, 5)
# )
This would also be nice to replace the clunky selectionId
for getting selected rows.
Is there one particular way you'd prefer to use? I think I'm leaning toward the second way so far, since it'd be easier to work with in R. But both would be fairly straightforward to implement.
If you ever want to create a PR for anything, I'd be happy to help review or get you started. That also reminds me, I haven't gotten around to writing any development/contributing documentation yet. I'll try to do that soon.
I like the second approach and I think a lot of shiny users will prefer that rather than having to write the JS calback functions. Another benefit would be that as you implement other ways to update the reactable through updateReactable
, I assume, you would be able to add that information to the output of getReactable
which I think would be useful.
Hi @glin
I am not sure whether this is something that falls under this issue or if I should open a new one but it looks like if you pass NA_real_
to updateReactable
for the selected
argument than it successfully deselects the row but the value of the input$selection
value becomes 1 rather than NULL
. See the example below:
library(shiny)
library(reactable)
ui <- fluidPage(
actionButton("select_btn", "Select rows"),
actionButton("clear_btn", "Clear selection"),
actionButton("clear_btn_real", "Clear Selection - NA_real_"),
reactableOutput("tbl"),
"Rows selected:",
verbatimTextOutput("rows_selected")
)
server <- function(input, output) {
output$tbl <- renderReactable({
reactable(
iris,
selection = "multiple",
selectionId = "selection",
onClick = "select",
details = function(index) paste("Row details for row:", index)
)
})
observeEvent(input$select_btn, {
# Select rows
updateReactable("tbl", selected = c(1, 3, 5))
})
observeEvent(input$clear_btn, {
# Clear row selection using NA or integer(0)
updateReactable("tbl", selected = NA)
})
observeEvent(input$clear_btn_real, {
# Expand all rows
updateReactable("tbl", selected = NA_real_)
})
output$rows_selected <- renderPrint({
print(input$selection)
})
}
shinyApp(ui, server)
This issue works for me. Nice catch, I've fixed that in https://github.com/glin/reactable/commit/9f05b906505a5b6d93f93bab0df98c6bc13535fc.
I've also added a getReactableState()
function to the development version: https://glin.github.io/reactable/reference/getReactableState.html
You can use getReactableState(outputId)
to get the current page
, pageSize
, number of pages
, and selected
rows all in a list. Or getReactableState(outputId, "page")
to get just a single value.
Here's an example of it in action: https://glin.github.io/reactable/articles/examples.html#get-the-state-of-a-reactable-instance
Is there a way to edit individual cells in reactable? something similar to DT?
Hi, how to get the current displayed record number in a page, I means the numbers that displayed at left down of a table : (1- 10 of 100 rows displayed)
Hi,
Is there any way to update the selected or expanded row in a
reactable
based on another user input?A simple example can be shown below showing the desired functionality as it can be done in the
DT
package with datatables. In this example, thereactable
is shown on the left hand side while thedatatable
is shown on the right. In both of these examples, if a row is selected than the respectiveselectInput
andtextOutput
are updated. However, on thedatatable
side when theselectInput
is updated the selected row in thedatatable
changes. This is done using thedataTableProxy
andselectRows
functions. Is there a way to do something similar to this with thereactable
? This would be an incredibly useful feature if available! Also, in addition to changing which row is selected, if there was a way to change which row is expanded, that would also be very useful!Example:
Thanks for the great package!