ConditionalPanels for each navbarpage in Shiny - r

I have a simple problem with Shiny: I'm using a navbarPage layout, and I have two different sidebars. I want the sidebar to be conditional on which page of the app the user is on.
That seems easy enough, and the following approach works fine at changing the sidebar panel, but with this approach my tab headers drop down from the top navbar and into the main panel. I Have tried various approaches to get them back into the navbar, which all haven't worked.
Suspect there's a very simple solution, any help gratefully received!
library(shiny)
ui <- navbarPage(title = "example",
sidebarLayout(
sidebarPanel(
conditionalPanel(condition = 'input.tabs==1',"sidebar 1"),
conditionalPanel(condition = 'input.tabs==2 | input.tabs==3',"sidebars 2&3")),
mainPanel(tabsetPanel(id="tabs",
tabPanel("About",value=1, "hello 1"),
tabPanel("parameters",value=2, "hello 2"),
tabPanel("outputs",value=3, "hello 3")
))))
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)

You don't need the tabsetPanel to achieve this, just assign the id to the navbarPage itself and see which one is clicked
library(shiny)
ui <- navbarPage(title = "example",
id = 'tabs',
tabPanel("About",value=1, "hello 1"),
tabPanel("parameters",value=2, "hello 2"),
tabPanel("outputs",value=3, "hello 3"),
sidebarPanel(
conditionalPanel(condition = 'input.tabs == 1',"sidebar 1"),
conditionalPanel(condition = 'input.tabs == 2 | input.tabs==3',"sidebars 2&3")
)
)
server <- function(input, output, session) {
observe({
print(input$tabs)
})
}
shinyApp(ui = ui, server = server)

Related

Create 2 sidebar panels stacked vertically, one with tabs, one without

I would like to have a sidebar panel with tabs, while it also has a shared element that doesn't change if you click the tabs.
Intuitively, this could be achieved if the sidebar panel could be split into 2 pieces where the upper has the tabsetPanel, and bottom the shared element, but I can't find anything that allows this. (e.g. pageWithSidebar ( headerPanel(), sidebarPanel(tabsetPanel()),sidebarPanel(),mainPanel())
Is this possible?
e.g. this gives me 2 sidebars next to each other and a main panel underneath the second:
library(shiny)
ui <- fluidPage(
sidebarPanel(
tabsetPanel(
tabPanel("analysis-settings1",
textInput("settings1",label = "set some options")),
tabPanel("analysis-settings2",
textInput("settings2",label = "Some other settings"))
)),
sidebarPanel(
actionButton(inputId = "go", label="Go"),
verbatimTextOutput("showsummarysettings")),
mainPanel("..")
)
server <- function(input, output) {
observeEvent(input$go, ignoreInit=TRUE, {
output$showsummarysettings <- renderText({
"analysis-settings1 include ... and analysis-settings2 include ..."
})
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
Please let me know if this doesn't solve your problem:
library(shiny)
ui <- fluidPage(
sidebarPanel(
tabsetPanel(
tabPanel("analysis-settings1",
textInput("settings1",label = "set some options")),
tabPanel("analysis-settings2",
textInput("settings2",label = "Some other settings"))
),
actionButton(inputId = "go", label="Go"),
verbatimTextOutput("showsummarysettings")),
mainPanel("..")
)
server <- function(input, output) {
observeEvent(input$go, ignoreInit=TRUE, {
output$showsummarysettings <- renderText({
"analysis-settings1 include ... and analysis-settings2 include ..."
})
})
}
# Run the app ----
shinyApp(ui = ui, server = server)

Disabling fileInput

I have one selectizeInput and one fileInput in my shiny app.
I want to keep fileInput disabled until some value is not selected in selectizeInput.
Also I want a popup message to select a value every time user clicks on fileInput.
How can I do that.
As others have mentioned, the shinyjs package is useful here. You could use enable, disable, or toggleState.
library(shiny)
library(shinyjs)
ui = fluidPage(
shinyjs::useShinyjs(),
selectizeInput("selector", label="Choose 2:", multiple=TRUE,
choices=letters[1:5], selected=letters[1:5]),
fileInput("file_inputer", label="upload file")#,
# dataTableOutput('table')
)
server = function(input, output) {
observe({
shinyjs::toggleState("file_inputer", length(input$selector) %in% 0:4)
})
observeEvent(input$file_inputer, {
showModal(modalDialog(
title="Do you want a header row?",
selectInput("option_selector", label="Choose an option",
choices=c("option 1", "option 2", "option 3")),
footer = tagList(actionButton("read_file", "Read File"),
modalButton("Cancel")
)
))
})
observeEvent(input$read_file, {
# do something with your option value
removeModal()
})
}
# Run the application
shinyApp(ui = ui, server = server)

Conflict between shinyBS::bsCollapse and shiny::conditionalPanel

I am using a shiny::conditionalPanel inside a shinyBS::bsCollapsePanel. I have logic in my app that depends on which shinyBS panel is active (i.e., expanded). This works fine until I activate the conditional panel. If I show the Shiny conditional panel, then the shinyBS collapse panel gets stuck as active even when the panel is inactive (i.e., closed).
How can I modify my code so that the collapsible panels only register as active if they are expanded?
In this example there is a text output indicating the active panel. Switching between panels works correctly unless the conditional panels are shown.
EDIT: It appears this bug may already be documented (https://github.com/ebailey78/shinyBS/issues/38) and there is a possible solution (https://github.com/ebailey78/shinyBS/pull/68/commits).
library(shiny)
library(shinyBS)
# Define UI logic
ui <- fluidPage(
htmlOutput("activePanel"),
shinyBS::bsCollapse(
id = "bsPanels",
shinyBS::bsCollapsePanel(
"Panel A",
value = "panelA",
checkboxInput("showPanelA",
"Show panel",
value = FALSE),
conditionalPanel(
condition = "input.showPanelA",
helpText("Panel A conditional content")
),
helpText("Panel A main content")
),
shinyBS::bsCollapsePanel(
"Panel B",
value = "panelB",
checkboxInput("showPanelB",
"Show panel",
value = FALSE),
conditionalPanel(
condition = "input.showPanelB",
helpText("Panel B conditional content")
),
helpText("Panel B main content")
)
)
)
# Define server logic
server <- function(input, output) {
output$activePanel <- renderText({
paste("<b>Active Panel:</b>", paste(input$bsPanels, collapse = ", "))
})
}
# Run the application
shinyApp(ui = ui, server = server)
There is some discussion of this issue on the shinyBS project page (https://github.com/ebailey78/shinyBS/issues/38). However, I had limited success with the proposed solutions.
The best solution I have found is to use shinyjs::showElement and shinyjs::hideElement.
library(shiny)
library(shinyBS)
library(shinyjs)
# Define UI logic
ui <- fluidPage(
useShinyjs(),
htmlOutput("activePanel"),
shinyBS::bsCollapse(
id = "bsPanels",
shinyBS::bsCollapsePanel(
"Panel A",
value = "panelA",
checkboxInput("showPanelA",
"Show panel",
value = FALSE),
uiOutput("condPanelA"),
helpText("Panel A main content")
),
shinyBS::bsCollapsePanel(
"Panel B",
value = "panelB",
checkboxInput("showPanelB",
"Show panel",
value = FALSE),
uiOutput("condPanelB"),
helpText("Panel B main content")
)
)
)
# Define server logic
server <- function(input, output) {
output$activePanel <- renderText({
paste("<b>Active Panel:</b>", paste(input$bsPanels, collapse = ", "))
})
# Logic for conditional panels
output$condPanelA <- renderUI({
helpText("Panel A conditional content")
})
observe({
if(input$showPanelA) {
show("condPanelA")
} else {
hide("condPanelA")
}
})
output$condPanelB <- renderUI({
helpText("Panel B conditional content")
})
observe({
if(input$showPanelB) {
show("condPanelB")
} else {
hide("condPanelB")
}
})
}
# Run the application
shinyApp(ui = ui, server = server)

Shiny - Jump to page of embedded PDF

I want to jump to a certain page of an embedded PDF in shiny. I use tags$iframe to display the PDF. I know that I have to expand the URL in tags$iframe to jump to a certain page of the PDF by adding #page=x, i.e. tags$iframe(style="height:785px; width:100%", src="http://www.pdf995.com/samples/pdf.pdf#page=3").
However, if I have multiple tabs and switch from tab 1 to tab 2 and back to tab 1, the PDF always shows page 1. I could reload the whole tab/PDF to jump back to page 3, but I don't want to do that!
I tried to use JavaScript but it doesn't work because document.getElementById doesn't work properly.
My code so far
library(shiny)
library(shinyjs)
ui <- tagList(
useShinyjs(),
tags$script('Shiny.addCustomMessageHandler("go_to_page", function(message) {
document.getElementById("show_pdf").contentWindow.PDFViewerApplication.page = 3;
});'),
fluidPage(
fluidRow(
column(6,
tabsetPanel(id = "tabs",
tabPanel(
"Tab 1",
uiOutput("show_pdf")
),
tabPanel(
"Tab 2",
uiOutput("show_pdf1"))
)
)
))
)
server <- function(input, output, session){
output$show_pdf <- renderUI({
tags$iframe(style="height:785px; width:100%", src="http://www.pdf995.com/samples/pdf.pdf#page=3")
})
output$show_pdf1 <- renderUI({
tags$iframe(style="height:785px; width:100%", src="http://www.pdf995.com/samples/pdf.pdf#page=4")
})
observe({
input$tabs
session$sendCustomMessage(type = 'go_to_page', message = runif(1))
})
}
shinyApp(ui = ui, server = server)
What do I have to change so that the code works properly?

Call updateTabItems from inside Shiny module

In my shiny app I have lots of valueBoxes, each representing a tabItem in the sidebar of the shinydashboard. When clicking on the valueBox the page should move to the correct tab.
Instead of copypasting the code lots of times I wrote a reusable module which renders the valueBox and changes the class of the valueBox into an actionButton. In the server part I have included an observeEvent which calls updateTabItems when the valueBox is clicked. But when clicked nothing happens. It seems that the module cannot manipulate the dashboard sidebar.
library(shiny)
library(shinydashboard)
value_box_output <- function(.id) {
ns <- NS(.id)
valueBoxOutput(ns("overview.box"))
}
value_box <- function(input, output, session, .value, .subtitle, .tab.name) {
ns <- session$ns
output$overview.box <- renderValueBox({
box1 <- valueBox(
.value,
.subtitle,
href = "#",
width = NULL
)
box1$children[[1]]$attribs$class <- "action-button"
box1$children[[1]]$attribs$id <- ns("button")
box1
})
observeEvent(input$button, {
print("clicked")
updateTabItems(session, inputId = "tabs", selected = .tab.name)
})
}
ui <- dashboardPage(
dashboardHeader(title = "Title"),
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("Overview", tabName = "Overview"),
menuItem("Tab 1", tabName = "Tab_1")
)
),
dashboardBody(
tabItems(
tabItem("Overview", value_box_output("tab")),
tabItem("Tab_1")
)
)
)
server <- function(input, output, session) {
callModule(value_box,
"tab",
.value = 33,
.subtitle = "Tab 1",
.tab.name = "Tab_1")
}
shinyApp(ui, server)
You can find the answer in this post: Accessing parent namespace inside a shiny module
Basically, in updateTabItems() inside a moulde, you need to call the parent's session, not the session of the modul.
Thus, add a variable for your session to callModule() and call it in updateTabItems().

Resources