6

I want when i start the application the tab panel tab2 = desactivated, and will be activated once i click the button in the first tab panel tab1, i tried with shinyjs and through CSS properties but i can not do that.

thanks for your help Alex

library(shiny)
library(shinyjs)
runApp(list(
ui = bootstrapPage(
tabsetPanel(
  tabPanel(title = "tab1", id="tab1",
           br(),
           actionButton("click", label = "View tab2 panel")),
  tabPanel(title = "tab2", id="tab2")
)
),
server = function(input, output, session){
}
))
DeanAttali
  • 25,268
  • 10
  • 92
  • 118
Hazem HASAN
  • 1,598
  • 2
  • 21
  • 38

3 Answers3

17

You need a bit of javascript to do this. Here's a solution using shinyjs. I also included some css to make it clear when the tab is disabled

jscode <- "
shinyjs.disableTab = function(name) {
  var tab = $('.nav li a[data-value=' + name + ']');
  tab.bind('click.tab', function(e) {
    e.preventDefault();
    return false;
  });
  tab.addClass('disabled');
}

shinyjs.enableTab = function(name) {
  var tab = $('.nav li a[data-value=' + name + ']');
  tab.unbind('click.tab');
  tab.removeClass('disabled');
}
"

css <- "
.nav li a.disabled {
  background-color: #aaa !important;
  color: #333 !important;
  cursor: not-allowed !important;
  border-color: #aaa !important;
}"

library(shiny)
library(shinyjs)
runApp(list(
  ui = fluidPage(
    useShinyjs(),
    extendShinyjs(text = jscode),
    inlineCSS(css),
    tabsetPanel(
      id = "navbar",
      tabPanel(title = "tab1", id = "tab1",
               br(),
               actionButton("btn", label = "View tab2 panel")),
      tabPanel(title = "tab2", id = "tab2")
    )
  ),
  server = function(input, output, session) {

    # disable tab2 on page load
    js$disableTab("tab2")

    observeEvent(input$btn, {
      # enable tab2 when clicking the button
      js$enableTab("tab2")
      # switch to tab2
      updateTabsetPanel(session, "navbar", "tab2")
    })
  }
))

You could also put the javascript in a separate file and use extendShinyjs(file = ...) instead of extendShinyjs(text = ...).

DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • Thank you alot, it works perfectly, i have another question if you have the time of course: i haven an shiny application witch updates an normally. all the explanation at : runGitHub("ghatfan99/dynamicQuery") if you can help me it will be a great help for my project. thanks – Hazem HASAN Jul 30 '15 at 14:00
  • sorry, I don't have time with to help with that. For more complex cases that are not simply SO questions I do consulting work for a fee – DeanAttali Jul 30 '15 at 17:49
  • Hello daatali, thanks for your response can you tell me how match you want to do that with the explanation of the strange behavior of my application? – Hazem HASAN Aug 03 '15 at 07:20
  • hi @HazemHASAN , you can contact me at http://deanattali.com/contact if you want to talk about that :) – DeanAttali Aug 03 '15 at 08:12
  • 1
    @DeanAttali this isn't working for me. I've tried putting console.logs inside the JS functions, but I'm not seeing anything register. However, inside R, the `observeEvent` is recognizing the button press, and evaluating `js` returns an environment. What exactly is the `js` object here? – Yu Chen Oct 01 '17 at 01:19
  • I just tried this with the latest shiny version and it worked fine. `js` is exported from the `shinyjs` package (it's the same as `shinyjs::js$` – DeanAttali Oct 01 '17 at 03:42
  • That doesn't work if the tab name (`name` argument for `disableTab` function) contains spaces. I tried to modify JS code to add quotes around the name, but I am getting errors from shinyjs about JS code parsing, so I am not sure what to do in this case. – donshikin Dec 26 '18 at 22:38
  • OK figured it out - just had to put JS code into separate file and enquote the name in CSS selector. Also added partial attribute matching into CSS for more flexibility (some of my tab names are actually dynamic, they are textOutput() elements rendered by Shiny, and it is easiest to select them by Shiny output ID) – donshikin Dec 26 '18 at 23:32
5

Looking at this 5 years later, I had to make this change to Dean's code to make it work:

extendShinyjs(text = jscode)

becomes

extendShinyjs(text = jscode, functions = c('disableTab','enableTab'))
Billy
  • 51
  • 1
  • 1
2

Some small clarifications on the arguments value, id, and value working from @DeanAttali's reprex:

library("shiny")
library("shinyjs")
library("V8") ## Required for shinyjs::extendShinyjs()

## JavaScript that dis/enables the ABILITY to click the tab (without changing aesthetics)
app_jscode <-
  "shinyjs.disableTab = function(name) {
    var tab = $('.nav li a[data-value=' + name + ']');
    tab.bind('click.tab', function(e) {
      e.preventDefault();
      return false;
    });
    tab.addClass('disabled');
  }
  shinyjs.enableTab = function(name) {
    var tab = $('.nav li a[data-value=' + name + ']');
    tab.unbind('click.tab');
    tab.removeClass('disabled');
  }"
## css snipit that makes it LOOK like we are/n't able click the tab (with outchanging functionality)
app_css <-
  ".nav li a.disabled {
    background-color: #aaa !important;
    color: #333 !important;
    cursor: not-allowed !important;
    border-color: #aaa !important;
  }"

ui = fluidPage(
  shinyjs::useShinyjs(),
  shinyjs::extendShinyjs(text = app_jscode),
  shinyjs::inlineCSS(app_css),
  navbarPage(title = "Navbar title!", id = "navbarid",
             tabPanel(title = "tab1", ## id and value args not needed
                      br(),
                      p("in tab 1."),
                      actionButton("btn", label = "toggle locked tabs")),
             tabPanel(title = "tab2", ## id and value args not needed
                      p("in tab 2."))
  )
)
server = function(input, output, session) {
  ## Disable tab2 on page load
  js$disableTab("tab2")
  
  observeEvent(input$btn, {
    ## Enable tab2 when clicking the button
    shinyjs::js$enableTab("tab2") ## On a tab's title
    ## Switch to tab2
    updateNavbarPage(session, "navbarid", "tab2") ## On navbar's id, tab's title
    #### Taking it further: 
    ## Also disable tab1 as a selection
    shinyjs::js$disableTab("tab1")
  })
}
shinyApp(ui = ui, server = server)

R_Pseudo
  • 146
  • 5