R Shiny - Build a tabsetPanel from a list from selectizeInput - r

I have been trying to develop this tabsetpanel for a while but without success. The goal is to assemble the tabs dynamically. After the user click the search button, the tabs will be assembled from the user's selection in selectizeInput. Each tab will have a specific content. When the user presses the search button again, the tabs must be built again with the information from selectizeInput without duplication.
I appreciate any help.
the result should be like this image:
library(shiny)
ui <- fluidPage(
title = "Examples of DataTables",
sidebarLayout(
sidebarPanel(
selectizeInput(
'state', 'State', choices = state.name, multiple = TRUE
),
actionButton("search", "Search"),
),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("tab1", verbatimTextOutput("tab1"))
)
)
)
)
server <- function(input, output) {
output$tab1 <- renderPrint({
"tab1"
})
}
shinyApp(ui, server)

Well, I figure it out using insertUI and removeUI. To loop the tabsetPanel I used do.call method and voila!!!

Related

Login to single tabPanel in Shiny

I have been trying to make a login for a single tabPanel in Shiny. I have used the shinyAlert method, (as described here: How to access Shiny tab ids for use with shinyalerts?) which works, but unfortunately, it shows parts of the tabPanel's content before the user is logged in.
Is there a way to change this? I am trying to figure out how to make the "backdrop" of the shinyAlert just a white page until the user is successfully logged in. I read that this might be possible with CSS, but it is unclear to me how.
Or is there another method to do this, that I haven't considered? I am pretty new to Shiny.
Edit: the relevant parts of the code.
ui <- fluidPage(navbarPage("Eksempel", theme = shinytheme("cerulean"),
tabPanel("Home", icon = icon("home"),
fluidRow(
box(
Title = "Welcome to the example layout",
width = 10,
solidHeader = TRUE,
"Welcome text")
)),
tabPanel("Prototype", icon = ("chart-line"),
fluidPage(tagList(
textInput("user", "User:"),
passwordInput("password", "Password:"),
uiOutput("secrets"))),
# other tabPanels
server <- function(input, output, session){
output$secrets <- renderUI({
req(input$user == "admin", input$password == "shiny")
fluidPage( #contents of tabPanel, containing different plots ect.
)
})
The contents of the fluidPage I am trying to hide works fine when I don't try to hide it.
You can use req in combination with a renderUI and uiOutput to hide stuff until someone authenticates.
library(shiny)
ui <- fluidPage(
tagList(
textInput("user", "User:"),
passwordInput("password", "Password:"),
uiOutput("secrets")
)
)
server <- function(input, output) {
output$secrets <- renderUI({
req(input$user == "admin", input$password == "stackoverflow")
wellPanel("Hello admin! These are the secrets!")
})
}
shinyApp(ui = ui, server = server)
If you want a more enterprise-ready approach, you can try ShinyProxy or Shiny-Server Pro.

Clear the main Panel to display the other reactive output in shiny r studio

I have a dataTableOutput in my main panel. Then I have an action button "Go". Once I click "Go" I want rHandsOutput to appear in the main panel but not beneath dataTableOutput. How can I remove dataTableOutput in the main panel and display rHandsOutput. In my current code both tables appearing together. Once I click "Go", the second table comes under the first table where I want to appear only second table (rHandsOutput) removing 1st table from the main panel.
Please help me!1
You can use a combination of insertUI and removeUI to make UI components dynamic. For example:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
actionButton(inputId = "go", label = "Go")
),
mainPanel(
fluidRow(
tags$div(id = "firstOutput",
dataTableOutput("myDataTable"))
),
fluidRow(
tags$div(id = "placeholder") # the dynamic UI will be inserted relative to this placeholder
)
))
)
server <- function(input, output) {
output$myDataTable <- renderDataTable(iris)
observeEvent(input$go, {
removeUI("div:has(>#firstOutput)")
insertUI(
selector = "#placeholder",
where = "afterEnd", # inserts UI after the end of the placeholder element
ui = fluidRow(
actionButton(inputId = "newButton", label = "A new button")))
})
}
shinyApp(ui = ui, server = server)
You can use showElement() and hideElement() from shinyjs:
observeEvent(input$go, {
shinyjs::hideElement(“firsttable”)
shinyjs::showElement(“rHandsOutput”)
})
Assuming the ID of the first table is “firsttable” and the ID of the second table is “rHandsOutput”, and the ID of the “Go” button is “go”.
Generate the ui dynamically.
Use uiOutput("someidentifier") in the ui.r and then fill it with your datatable with the following in server.r
output$someidentifier <-
renderUI({
dataTableOutput("datatableidentifier")
})
output$datatableidentifier <- renderDataTable(iris)
uiOutput takes the place (in ui.r) of whatever ui element you want to add dynamically. The necessary code for that ui then moves to renderUI in server.r.

opening a new empty shiny ui through actionbutton

My objective is to create a ShinyApp that opens a new empty UI whenever user clicks on submitButton.
Currently this is my code below. If the user types something in the text box and press Submit. The app shows what the user typed in the main panel. However I dont want to see the text, instead when the user clicks on the submit button , it should open a new empty UI.
ui = shinyUI(fluidPage(
titlePanel("submitButton example"),
fluidRow(
column(3, wellPanel(
textInput("text", "Text:", "text here"),
submitButton("Submit")
)),
verbatimTextOutput("text")
)
)
)
server = function(input, output) {
output$plot1 <- renderPlot({
hist(rnorm(input$n))
})
output$text <- renderText({
paste("Input text is:", input$text)
})
}
shinyApp(ui=ui, server=server)
Is this possible ? Any tips or pointers are appreciated.
Well, this is not yet very functional, but does what you asked for.
ui = shinyUI(fluidPage(
titlePanel("submitButton example"),
fluidRow(
uiOutput("newWindowContent", style = "display: none;"),
tags$script(HTML("
$(document).ready(function() {
if(window.location.hash != '') {
$('div:not(#newWindowContent)').hide();
$('#newWindowContent').show();
$('#newWindowContent').appendTo('body');
}
})
")),
a(href = "#NEW", target = "_blank",
actionButton("Submit", "Submit")
)
))
)
server = function(input, output) {
output$newWindowContent <- renderUI({
"Welcome to your new window!"
})
}
shinyApp(ui=ui, server=server)
The app is created, such that the ui created in newWindowContent is displayed in the new window. Sadly, new windows are somewhat cut off from the parent page, such that there is no easy way to configure each page independently. At the moment, all show the same content. None have reactivity features. I guess there can be initial configurations, if one uses the window's hash. But this works only client sided.
Nevertheless, it's a good start!

Using conditionalPanel (or other methods) to create a temporary banner that disappears if user navigates away

I want to create a welcome message for when a user first opens the shiny webpage. Currently I have it such that it is constantly on the first tabPanel. Is there a way to make it disappear when the user navigates away and then back to that panel?
fluidRow(
column(width=12,
tabsetPanel(type = "tabs", id = "tabs1",
tabPanel("Express Usage", wellPanel("Welcome! Please select the libraries you are interested in viewing from below and use the tabs to navigate between graphs. It is best to limit your selection to no more than 5 libraries at a time"), plotOutput("express_Plot", height=400)),
tabPanel("Juvenile Usage", plotOutput("juvenile_Plot", height=400)),
tabPanel("test", h3(textOutput("text_test")))))
),
You can set the value attribute for all your tabPanels accordingly.
In this way, you can tell, in server.R, which tab is currently selected by reading input$tabs1, where tabs1 is the id you set for the tabsetPanel.
Replace the wellPanel with a uiOutput element, and update the UI elements according
to:
The current panel.
The times the panel has been visited.
ui.R
library(shiny)
shinyUI(fluidPage(
fluidRow(
column(width=12,
tabsetPanel(type = "tabs", id = "tabs1",
tabPanel("Express Usage",
uiOutput("welcome"), # replace the wellPanel
plotOutput("express_Plot", height=400), value="ex_usage"),
tabPanel("Juvenile Usage", plotOutput("juvenile_Plot", height=400), value="juv_usage"),
tabPanel("test", h3(textOutput("text_test")))), value="test")
)
)
)
server.R
library(shiny)
shinyServer(function(input, output, session){
visits <- reactiveValues(times = 0)
output$welcome <- renderUI({
if (input$tabs1 == "ex_usage") {
isolate(visits$times <- visits$times + 1)
if (isolate(visits$times) == 1) {
return (wellPanel("Welcome! Please select the libraries you are interested in viewing from below and use the tabs to navigate between graphs. It is best to limit your selection to no more than 5 libraries at a time"))
}
else {
return ()
}
}
})
})

Attach conditionalPanel to specific button instead of general page load in Shiny app (R)

I have a conditionalPanel that I am using to show the progress of a calculation on one of my Shiny pages. It calls some javascript to show the time progress of the calculation.
ui.R
conditionalPanel("updateBusy() || $('html').hasClass('shiny-busy')",
id='progressIndicator',
"Calculating...",
div(id='progress',includeHTML("timer.js")))
This fires whenever any button or selector is used on the page. In other words, anything that causes the page to reload activates the conditionalPanel. How can I make it so that it only activates for a specific selector or button. I am assuming it needs to be tied into an "isolate" expression or something?
I dont have your timer.js so a "HELLO" is displayed instead. When the first plot is recalculated a progress is displayed. It is not displayed for the second plot.
runApp(list(ui = fluidPage(
# Application title
titlePanel("Hello Shiny!"),
sidebarLayout(
# Sidebar with a slider input
sidebarPanel(
numericInput('n', 'Number of obs', 100),
conditionalPanel("$('#plot').hasClass('recalculating')",
id='progressIndicator',
"Calculating...",
div(id='progress',"HELLO")
),
numericInput('m', 'Second set Number of obs', 100)
),
mainPanel(
plotOutput('plot'),
plotOutput('plotA')
)
)
),
server = function(input, output) {
output$plot <- renderPlot({ Sys.sleep(4)
hist(runif(input$n))
})
output$plotA <- renderPlot({ hist(runif(input$m)) })
}
)
)

Resources