In R Shiny, use textOutput to dynamically populate downloadbutton's label - r

In R Shiny I am trying to dynamically set a download button's label using reactive renderText and textoutput.
It works as expected but the label is always shown in the new line, and hence the button looks wacky next to a regular button
as shown here
Backend logic is -
In server.R, an input field's value is used to generate conditional labels
output$mycustomlabel <- renderText({ if(input$inputtype=="One") return("Download label 1") else return("Download label 2")})
Then in UI.R, that label is used as
downloadButton("download.button.test", textOutput("mycustomlabel"))
Can someone guide why does it display text on new line, and how can I keep it on same line?

If you want to change the button label you probably need to update it with javascript.
An easier approach could be to have two different buttons and use conditional panels to display one of the buttons:
ui <- fluidPage(
radioButtons('inputtype', 'Set label', c('One', 'Two')),
conditionalPanel(
'input.inputtype == "One"',
downloadButton('btn1', 'Download label 1')
),
conditionalPanel(
'input.inputtype == "Two"',
downloadButton('btn2', 'Download label 2')
)
)
Note that with this approach you do need two observers in the server function.

I'm doing this same thing with a dynamic label on a downloadButton. In my case, I want the user to choose between downloading a dataframe as an Excel file or a CSV file.
Here's what I'm doing:
In the ui definition, where you want the button to show up, use
uiOutput( 'myCustomButtonUI' )
In the server definition, include:
output$myCustomButtonUI <- renderUI({
myCustomLabel <- 'Placeholder'
if( input$inputtype == 'One' ) myCustomLabel <- 'Download Label 1'
if( input$inputtype == 'Two' ) myCustomLabel <- 'Download Label 2'
downloadButton( inputId = 'download.button.test',
label = myCustomLabel )
})
output$download.button.text <- downloadHandler(
filename = "<some filename>",
content = .... <go look up downloadHandler() if you're unfamiliar> ..."
)
The idea is that, because you want your button to be dynamic, it needs to be rendered on the server side. The output of the server side is a tiny piece of UI that is placed in your larger UI by the uiOutput function.

Related

Show/Hide button on tab select R shiny

I have a button in my ui.R that I want to be shown only when "Summary" tab is selected, so I thought of this code
fluidRow(
column(4,
column(12,id="sub",
actionButton("submit", "SUBMIT", width = "100%"))),
column(8,
bsCollapse(id = "collapse7", open = "Results",
bsCollapsePanel("Results",
tabsetPanel(
tabPanel("Summary",
tags$script(HTML("document.getElementById('sub').style.visibility = 'visible';")))
tabPanel("Plot",
tags$script(HTML("document.getElementById('sub').style.visibility = 'hidden';"))))
))))
The problem is, the button is hidden even though in my first tab it should be visible and also when i go to Plots and back to Summary, the button stays hidden.
After looking at: How to use tabPanel as input in R Shiny?
I decided to play with observeEvent and the input$tabset option. The result is 100% working and it's really simple. Here's the code:
observeEvent(input$choices, {
choice = input$choices
if(choice == "Summary")
{
runjs(
"document.getElementById('submit').style.visibility = 'visible';"
)
}
else
{
runjs(
"document.getElementById('submit').style.visibility = 'hidden';"
)
}
})
Also, I found out why my previous code wasn't working, it was due to the fact that when the UI was initialized, the button element kept the last style modification (the hidden one) and it didn't change depending on the tab I have selected, since its not reactive.

shiny checkbox unchecks - cross-referring to inputs in same renderUI call

I intended to have some optional extra buttons appearing in my shiny app using renderUI. I would prefer to have new buttons inserted in the one and same renderUI call. I wrote a renderUI expession were the second button only is rendered if input of fist button is not null and(&&) is TRUE. It does not work as first button rapidly unchecks itself again whenever checked. I made a solution by splitting into two renderUI calls.
My question are:
Why exactly does the first code piece fail?
Would it be possible to achieve what the second code piece does in only one renderUI call?
.
library(shiny)
ui = fluidPage(
uiOutput("checkUI")
)
server = function(input,output) {
output$checkUI = renderUI({
list(
checkboxInput('check1',"check me first"),
if(!is.null(input$check1)&&input$check1==T) {
checkboxInput('check2',"check me to win")
} else {
NULL
}
)
})
}
shinyApp(ui,server)
but this works...
ui = fluidPage(
uiOutput("checkUI"),
uiOutput("textUI")
)
server = function(input,output) {
#UI first button
output$checkUI = renderUI({
list(
checkboxInput('check1',"check me first")
)
})
#UI second button
output$textUI = renderUI({
list(
if(!is.null(input$check1) && input$check1)
checkboxInput('check2',"check me to win") else NULL
)
})
}
shinyApp(ui,server)
Your first piece of code fails because the renderUI runs every time there is a change in input, so when you check the first check box. Since you have:
checkboxInput('check1',"check me first")
The renderUI immediately resets the input$check1 and then the renderUI is run again, unsetting the checkbox. This is why the second checkbox briefly flashes.
Luckily this is a common problem, so there is a Shiny solution to this with conditionalPanels:
library(shiny)
ui = fluidPage(
checkboxInput('check1',"check me first"),
conditionalPanel(
condition = "input.check1 == true",
checkboxInput("check2", "check me to win")
)
)
server = function(input,output){
}
shinyApp(ui,server)

Get available options from shiny widget

Is it possible to get the available options for a shiny widget (ie. all of the possible checkboxes from a checkboxInput)?
I have some checkbox input where the options available to check are dependent on other input -- they are updated by observers. Then, suppose I want a button that the user can click and the all of the currently available checkboxes will be checked.
Here is an illustrative example, where I try to update the checkboxes using updateCheckboxGroupInput and the variable input$options. However, this doesn't work because input$options is only the currently selected boxes, so the button does nothing.
Is there already variable that contains all the available checkboxes, or is necessary to maintain another reactive variable with this information?
library(shiny)
shinyApp(
shinyUI(
fluidPage(
uiOutput('ui')
)
),
shinyServer(function(session, input, output) {
output$ui <- renderUI({
inputPanel(
checkboxGroupInput('options', 'Current Options:',
choices=letters, selected='a', inline=TRUE),
column(width = 2,
actionButton('subset', 'Subset the options'),
actionButton('selectAll', 'Select All'))
)
})
## Observers for buttons
observeEvent(input$subset,
updateCheckboxGroupInput(session,
inputId='options',
choices=sample(letters, 10),
inline=TRUE)
)
observeEvent(input$selectAll,
updateCheckboxGroupInput(session,
inputId='options',
## *** What do I put here for selected? ***
selected=input$options,
inline=TRUE)
)
})
)
There isn't a simple Shiny builtin way to do that. You'd have to either use JavaScript to see what the options are, or store the options in a reactive variable

use variable in UI of R Shiny?

I have created quite a large app that I now want to extent by introducing tabs. So far I have, as an example:
ui.R
shinyUI(
#OLD CODE
)
server.R
(
#OLD CODE
)
What I would like to do:
ui.R
shinyUI(
tabsetPanel(
"Tabs",
tabPanel("Old Code",value="tb1"),
tabPanel("New Code",value="tb2"),
id = "nlp"
),
if (id=="tb1") {
#OLD CODE
} else if (id=="tb2") {
#New Code
} else {
#Do nothing
}
How do I get the if function to recognise id as a variable?
When I run the script it comes up with the error object 'id' not found. So then I've tried input$id and output$id with no avail.
I have also tried going to the server.R and tried
Server.R
output$id <- renderText("id")
also didn't work when trying to bring that back into the UI
and I have also tried
Server.R
output$id <- reactive({input$id})
this also didn't work when I tried to use it in the UI. Where am I going wrong and how can I use the Id variable in the UI?
Thanks
Based on the Shiny Tabsets example, you should be putting the UI elements into each call to tabPanel, like so:
shinyUI(
tabsetPanel(
tabPanel(
title = "Old Code",
plotOutput('plot1'),
plotOutput('plot2')
),
tabPanel(
title = "New Code",
tableOutput('table')
),
id = "nlp"
)
)
Unless you are trying to do more than necessary, your code does not need to know what tab the client has selected. I may be wrong (please do not think I'm an authority on shiny), I think the elements within the not-selected tabs are not unnecessarily recalculated (unless dependencies exist and require it).

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 ()
}
}
})
})

Resources