DT icon indicating copy to clipboard operation
DT copied to clipboard

rows_selected property is not updated if data source is changed and its datatable is in another tab

Open paulimer opened this issue 2 years ago • 3 comments

Hi, I have an issue with the behavior of DT and the property input$table_rows_selected. When the data source changes, and the table is in focus (in the current tab), the rows_selected variable is set back to NULL. However, if the table is not in focus, rows_selected is too lazy and keeps the same value, until the table is redrawn, and only at this point the rows_selected variable is set back to NULL. A reproducible example: (one needs to select rows on the first tab, change tab, change the data, see that rows are still selected, visit the first tab, rows are then unselected and the table in the second tab is empty)

library(shiny)
library(DT)

ui <- fluidPage(
  tabsetPanel(
    tabPanel("table", DTOutput("tab")),
    tabPanel(
      "interaction", 
      selectInput("change", "Change data source",
                  choices = c("mtcars", "iris")),
      DTOutput("sel")
    )
  )
)


server <- function(input, output, session) {
  data <- eventReactive(input$change,{
    if(input$change == "mtcars") {
      mtcars
    } else if (input$change == "iris") {
      iris
    }
  }
  )
  output$tab <- renderDT(
    data()
  )
  output$sel <- renderDT({
    data()[input$tab_rows_selected,]
  })
}

shinyApp(ui, server)

Thanks in advance! xfun::session output :

R version 4.1.3 (2022-03-10)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: Fedora Linux 35 (Workstation Edition), RStudio 2021.9.2.382

Locale:
  LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
  LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
  LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

Package version:
  base64enc_0.1.3   crosstalk_1.1.1   digest_0.6.27     DT_0.17           fastmap_1.1.0     graphics_4.1.3   
  grDevices_4.1.3   htmltools_0.5.2   htmlwidgets_1.5.3 jsonlite_1.7.2    later_1.2.0       lazyeval_0.2.2   
  magrittr_2.0.1    methods_4.1.3     promises_1.2.0.1  R6_2.5.1          Rcpp_1.0.8        rlang_0.4.11     
  stats_4.1.3       utils_4.1.3       yaml_2.2.1

By filing an issue to this repo, I promise that

  • [x] I have fully read the issue guide at https://yihui.name/issue/.
  • [x] I have provided the necessary information about my issue.
    • If I'm asking a question, I have already asked it on Stack Overflow or RStudio Community, waited for at least 24 hours, and included a link to my question there.
    • If I'm filing a bug report, I have included a minimal, self-contained, and reproducible example, and have also included xfun::session_info('DT'). I have upgraded all my packages to their latest versions (e.g., R, RStudio, and R packages), and also tried the development version: remotes::install_github('rstudio/DT').
    • If I have posted the same issue elsewhere, I have also mentioned it in this issue.
  • [x] I have learned the Github Markdown syntax, and formatted my issue correctly.

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

paulimer avatar Mar 29 '22 14:03 paulimer

A small update : I just learned about outputOptions, and its suspendWhenHidden argument. I tried to use it, as it seemed to be something I would want to solve my problem.

In the reproducible example, one can add outputOptions(output, "tab", suspendWhenHidden = FALSE) line 29, and it should rerender the table when input$change... well, changes. But the behavior seems to me more hectic :

  • the input$TableID_rows_selected does not update with this option either (expected set back to NULL)
  • When one switches to iris in the interaction tab, the table switches as well. When one selects mtcars back, and goes back to the first table, it is actually empty. This really seems like a bug. A video to document the issue : dt_issue

paulimer avatar Apr 06 '22 15:04 paulimer

Not sure to understand. Is it ok like this?

library(shiny)
library(DT)

ui <- fluidPage(
  tabsetPanel(
    tabPanel("table", DTOutput("tab")),
    tabPanel(
      "interaction", 
      selectInput("change", "Change data source",
                  choices = c("mtcars", "iris")),
      DTOutput("sel")
    ),
    id = "tabset"
  )
)


server <- function(input, output, session) {
  
  data <- eventReactive(input$change, {
    if(input$change == "mtcars") {
      mtcars
    } else if (input$change == "iris") {
      iris
    }
  })
  
  subsetdata <- reactiveVal()
  
  output$tab <- renderDT(
    data()
  )
  proxy <- dataTableProxy("tab")
  
  selectedRows <- eventReactive(input$tab_rows_selected, {
    input$tab_rows_selected
  })
  
  observeEvent(input$tabset, {
    if(input$tabset == "table") {
      selectRows(proxy, selectedRows())
    } 
  }, priority = 10)

  observeEvent(list(input$tabset, input$change), {
    subsetdata(data()[selectedRows(), ])
  }, priority = 1)
  
  output$sel <- renderDT({
    subsetdata()
  })
}

shinyApp(ui, server)

stla avatar Apr 06 '22 17:04 stla

Thanks a lot for the answer! What I was looking for is that no rows are selected if the data changes, because the rows selected only make sense relative to the initial data. This is what happens when the table is always in focus. In my mind, outputOptions(output, "tab", suspendWhenHidden = FALSE) should be the solution, to enforce the normal behavior even out of focus. However, as shown in the video, this does not work. But indeed I can put the equivalent of :

observeEvent(data(), {
  selectRows(proxy(), NULL)
})

in my application. I think that the suspendWhenHidden solution should work as well.

paulimer avatar Apr 11 '22 08:04 paulimer