rstudio / crosstalk

Inter-htmlwidget communication for R (with and without Shiny)
http://rstudio.github.io/crosstalk
Other
290 stars 53 forks source link

Fix #40: SharedData across shiny modules #114

Closed jcheng5 closed 3 years ago

jcheng5 commented 3 years ago

The bug: SharedData objects constructed inside Shiny modules, were not returning any values for sd$selection() and other reactive methods. This is because the id sent to the client and the id used by the server weren't the same--the server version had the module's namespace automatically prefixed. With this fix, the server uses the same id as the client.

Implementation notes

SharedData group should transcend modules (it's a global namespace). This isn't as crazy as it sounds, because the default group value is a random ID.

SharedData$new(..., group = session$ns("groupname")) can be used to opt into namespaces if that's desired.

Note that this change doesn't break a scenario that works today; before this commit, the reactive accessors on SharedData that originated in modules, simply did not work.

Testing notes

Run the following app. Select some points on the plot. Without the fix, the reported number of selected points is 0; with the fix, a correct number is reported. (Note that it might sometimes seem like the reported number is a little too high--this is because of overplotted points, and is almost certainly actually the correct number.)

library(shiny)
library(crosstalk)
library(plotly)

modUI <- function(id) {
  ns <- NS(id)
  tagList(
    p(
      "Number of points selected:",
      textOutput(ns("count"), container = strong)
    ),
    plotlyOutput(ns("plotly1"))
  )
}

mod <- function(id) {
  moduleServer(id, function(input, output, session) {
    sd <- SharedData$new(cars, group = "a")
    output$plotly1 <- renderPlotly({
      plot_ly(sd, type = "scatter", mode = "markers", x = ~ speed, y = ~ dist) %>%
        highlight("plotly_selected")
    })
    output$count <- renderText({
      sum(sd$selection())
    })
  })
}

ui <- basicPage(
  p(
    strong("Instructions:"),
    "Select some points in the plot, and make sure ",
    "'Number of points selected:' shows the correct value."
  ),
  hr(),
  modUI("one")
)

server <- function(input, output, session) {
  mod("one")
}

shinyApp(ui, server)
jcheng5 commented 3 years ago

Fixes #40