6

I need to select a tab from a tabset in R Markdown document (with Shiny runtime).

I followed the example in How to select a specific tabPanel in Shiny, and tried to adapt it to R Markdown. I added ids to the tabset / tab, and used them in the updateTabsetPanel() call, but it doesn't seem to work. (I used the names that pop-up when inspecting the individual HTML elements in the resulting dashboard.)

How can I select the "Chart3" tab from the tabset by clicking the button?

EDIT: I need to be able to select a specific tab programmatically (e.g. via observeEvent() call), not just on start-up.

---
title: "Tabset Column"
output: flexdashboard::flex_dashboard
runtime: shiny
---
    
Column 
-------------------------------------
    
### Chart 1
    
```{r}
actionButton("switch_tab", "Switch tab", width=200)
```
   
Column {#mytabset .tabset}
-------------------------------------
   
### Chart 2

```{r}
```   
 
### Chart 3 {#mytab}
    
```{r}
observeEvent(input$switch_tab, {
    updateTabsetPanel(session, inputId = "section-mytabset", selected = "#section-mytab")
})
```
landroni
  • 2,902
  • 1
  • 32
  • 39
  • might be of interest : https://stackoverflow.com/q/61458456/13513328 – Waldi Feb 17 '21 at 23:22
  • 1
    @Waldi Interesting. Ideally I would prefer a solution that doesn't involve (complex) JavaScript code. Native R/Shiny solution (e.g. `updateTabsetPanel()` or similar) would be best. – landroni Feb 18 '21 at 00:14

2 Answers2

4

The {.active} attribute could answer your question when launching the dashboard (static solution), and works with html_document :

---
title: "Active Tabset"
output: html_document
---
    

Column {.tabset}
-------------------------------------
   
### Tab 1

Some text
 
### Tab 2 {.active}

Some other text

enter image description here

Unfortunately, this didn't work with Flexdashboard :

---
title: "Active Tabset"
output: flexdashboard::flex_dashboard
---
    

Column {.tabset}
-------------------------------------
   
### Tab 1

Some text
 
### Tab 2 {.active}

Some other text

enter image description here

The issue has already been signaled here but was closed because of automatic lock.
The waiting period in order to comply with RMarkdown issue guide being over, I filed a new issue with the Minimal Reproducible Example above.

EDIT : This request has been taken into account, so this should soon work with Shiny Dashboard.

Waldi
  • 39,242
  • 6
  • 30
  • 78
  • If I understand correctly `{.active}` would be a static solution, that only works on start-up. I've now edited the question to clarify that I would need to be able to change tabs programmatically (e.g. via `observeEvent()` call). (I kept it out of the MRE to keep it simple.) – landroni Feb 17 '21 at 22:33
  • 1
    Yes, I understood a static solution, thanks for the clarification! – Waldi Feb 17 '21 at 22:39
  • 1
    FYI, static `{.active}` has been corrected on `ShinyDashboard` and should soon be available, see my edit. – Waldi Feb 24 '21 at 08:24
  • Nice they fixed it so quickly. This will be handy when it's released. – landroni Feb 26 '21 at 17:09
4

Instead of an observeEvent you could wrap the actionButton itself in an tags$a and link to #section-mytab. Note that you have to add section- before the tab name when using runtime: shiny.

Does this solve your problem or do you need it to work with observeEvent?

---
title: "Tabset Column"
output: flexdashboard::flex_dashboard
runtime: shiny
---

Column 
-------------------------------------
  
### Chart 1
  
```{r, echo = FALSE}
tags$a(href = "#section-mytab",
  shiny::actionButton("btn1", "go to mytab")
       )
```

Column {.tabset}
-------------------------------------
    
### Chart 2

```{r}

```   
  
### Chart 3 {#mytab}
  
```{r}

```

If needed, the logic above can be combined with observeEvent using {shinyjs} and a non-visible actionButton. The trick is here, that we still use an actionButton to trigger the tab. But the actual button is not shown display: none (it is important, that the button is not set to hidden, since this will prevent it from being clicked). We then create another actionButton which is observed by an observeEvent. This can trigger other calculations etc. and finally a click on the actionButton which is not shown. If you have more pages and want to jump from page 1 to, say, tab 3 on page 2, then we would need two clicks: one changing the page and one activating the tab. But we can all trigger this inside the observeEvent. Its hacky and doesn't look like good code, but on the plus side it works, even without a custom javascript function.

---
title: "Tabset Column"
output: 
flexdashboard::flex_dashboard
runtime: shiny
---

```{r global, echo = FALSE}
library(shiny)
library(shinyjs)
useShinyjs(rmd = TRUE)
```


Column 
-------------------------------------
  
### Chart 1

```{r, echo = FALSE}
observeEvent(input$btn1, {
  # do some calculations here
  click("btn2")})
 
shiny::actionButton("btn1", "do something")

tags$a(href = "#section-mytab",
  # set this button to `display: none;` but *not* to `hidden`
  shiny::actionButton("btn2", "go to mytab", style = "display: none")
  )
```

Column {.tabset}
-------------------------------------

### Chart 2

```{r}

```   
  
### Chart 3 {#mytab}
  
```{r}

```
TimTeaFan
  • 17,549
  • 4
  • 18
  • 39
  • Yes, ideally I would need the flexibility of an `observeEvent`. In my case this is part of a more complex routine that lives in an `observeEvent`. – landroni Feb 23 '21 at 02:46
  • 1
    @landroni: we can combine my approach with an `observeEvent`. It's kinda of a hack, but it works. – TimTeaFan Feb 23 '21 at 15:11
  • This is a nice hack, thanks. I think this should work for my purpose. For activating the button, is there a way to `click` the button without `shinyjs`? – landroni Feb 25 '21 at 19:04
  • @landroni: I haven't figured out a way to do it. It's either {shinyjs} or raw javascript. – TimTeaFan Feb 25 '21 at 22:03
  • I see, `shinyjs` works just fine for me -- I was mostly curious. The minimal example works nicely here, without issues. But for whatever reason the code doesn't work in my actual dashboard. I am trying to debug it, but I can't seem to isolate what makes it fail. (The invisible button `btn2` works fine, and if I make it visible and click on it then it will switch tabs, BUT for whatever reason I fail to activate it from the `observeEvent`. And again, the code works just fine in the MRE.) I'll try to debug some further and report back. – landroni Feb 25 '21 at 23:14
  • Is the tab on a different page? In this case we would need two `click`s. – TimTeaFan Feb 25 '21 at 23:15
  • I considered this possibility, but it doesn't seem to be it. I have a `sidebar`, one page and four tabs. I remodeled the MRE to this layout and the code still works fine (I put all of the buttons in the sidebar). In both documents I do `useShinyjs(rmd = TRUE)`. If I click on the "invisible" button (`btn2`, made visible for debugging), then it switches tabs without issues. If I click on `btn1`, the `observerEvent` triggers because I can see the debugging message printed in the console, but the `click("btn2")` call seems to fail. – landroni Feb 25 '21 at 23:25
  • Sounds like a very interesting debugging challenge. Have you verified the id of the invisible button in the DOM inspector. This is the first thing that comes into my mind. If the mouse click works and the `observeEvent` too than the missing link has to be either {shinyjs} or a mismatch in id argument and actual id. – TimTeaFan Feb 25 '21 at 23:34
  • Yes, the inspector shows the button with `id="btn2"`, which is the same as in the call `click("btn2")`. Can also rule out an issue with `shinyjs` or its version, because the MRE works. – landroni Feb 25 '21 at 23:47
  • 1
    It looks like the issue was coming from the chunk containing the `useShinyjs(rmd = TRUE)` call. In the MRE it was `echo = FALSE`, and this works (in my actual dashboard as well). Instead in my dashboard the chunk was originally `include=FALSE`, and that seems to have been causing the issue. My best guess is that `useShinyjs` generates output that needs to be included in the knitted document for its calls to work (e.g. `click`). Seems to work now, thanks again! – landroni Feb 26 '21 at 00:13