user8954262
user8954262

Reputation: 138

Flexdashboard doesn't work with Shiny URL state

I am trying to combine flexdashboard with Shiny state bookmarking. When used alone (example from the docs) Shiny app works fine, but when put in flexdasboard, url is not updated:

---
title: "Untitled"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
    runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
```

Column {data-width=650}
-----------------------------------------------------------------------

### Chart A

```{r}

shinyApp(
  ui=function(req) {
    fluidPage(
      textInput("txt", "Text"),
      checkboxInput("chk", "Checkbox")
    )
  },
  server=function(input, output, session) {
    observe({
      # Trigger this observer every time an input changes
      reactiveValuesToList(input)
      session$doBookmark()
    })
    onBookmarked(function(url) {
      updateQueryString(url)
    })
  },
  enableBookmarking = "url"
)

```

Is this even possible? Compared to standalone execution:

shinyApp(
  ui=function(req) {
    fluidPage(
      textInput("txt", "Text"),
      checkboxInput("chk", "Checkbox")
    )
  },
  server=function(input, output, session) {
    observe({
      # Trigger this observer every time an input changes
      reactiveValuesToList(input)
      session$doBookmark()
    })
    onBookmarked(function(url) {
      updateQueryString(url)
    })
  },
  enableBookmarking = "url"
)

it looks like onBookmarked (and similar events like onBookmark, onRestore and onRestored) are never triggered.

Upvotes: 7

Views: 964

Answers (1)

greg L
greg L

Reputation: 4124

Bookmarking isn't supported in Shiny apps embedded in R Markdown documents.

See discussion here: https://github.com/rstudio/shiny/pull/1209#issuecomment-227207713

Sounds like it's technically possible, but tricky to do. For example, what happens if there are multiple apps embedded in the document? Also, apps are embedded as iframes, so there would have to be some wiring up to be done to allow these apps to access/modify their parent window's URL.


However, bookmarking does work with embedded Shiny components (rather than full applications).

---
title: "Untitled"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
runtime: shiny
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
enableBookmarking("url")
```

```{r, include=FALSE}
observe({
  reactiveValuesToList(input)
  session$doBookmark()
})

onBookmarked(function(url) {
  updateQueryString(url)
})

output$content <- renderUI({
  tagList(
    textInput("txt", "Text"),
    checkboxInput("chk", "Checkbox")
  )
})
```

Column {data-width=650}
-----------------------------------------------------------------------

### Chart A

```{r}
fluidPage(
  uiOutput("content"),
  selectInput("sel", label = "Select", choices = c(10, 20, 30), selected = 10)
)
```

You can also use Prerendered Shiny Documents, although bookmarking would not work 100% the same since the UI is pre-rendered. Any static UI would have to be manually restored with bookmarking callbacks, but dynamic UI would be restored just fine.

---
title: "Untitled"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
runtime: shiny_prerendered
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
enableBookmarking("url")
```

```{r, context="server"}
observe({
  reactiveValuesToList(input)
  session$doBookmark()
})

onBookmarked(function(url) {
  updateQueryString(url)
})

# Static inputs are pre-rendered, and must be manually restored 
onRestored(function(state) {
  updateSelectInput(session, "sel", selected = state$input$sel)
})

# Dynamic inputs will be restored with no extra effort
output$content <- renderUI({
  tagList(
    textInput("txt", "Text"),
    checkboxInput("chk", "Checkbox")
  )
})
```

Column {data-width=650}
-----------------------------------------------------------------------

### Chart A

```{r}
fluidPage(
  uiOutput("content"),
  selectInput("sel", label = "Select", choices = c(10, 20, 30), selected = 10)
)
```

Upvotes: 6

Related Questions