How to disable all Shiny UI elements, including a downloadButton - r

This answer explains how can one disable/enable all UI elements in a Shiny app.
Among the two solutions given, the one I am interested in uses the shinyjs package (I'd rather not play with javascript directly).
My problem is that UI elements of the class downloadButton are not listed as elements of input.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
tagList(
downloadButton("downloadBtn", "Download button"),
actionButton("printBtn", "Print and disable all members of input")
)
)
server <- function(input, output) {
observeEvent(input$printBtn, {
print (names(input))
for(n in names(input))
shinyjs::disable(id=n)
})
}
shinyApp(ui = ui, server = server)
When I click on the "Print all members of input", only "printBtn" is printed ("downloadBtn" is not).
Hence, since downloadButton is not a member of input, disabling it by looping over all the elements of input - and disabling them one by one does not work.
Is there an elegant workaround that can be used in order to disable all of the elements?

Related

Is it possible to display an info text when hovering over a R shiny selectInput?

I am currently building a shiny app to build biological networks. To build them, you can choose between many different parameters, which i included in different selectInputs or numericInputs.
Is it possible to have some kind of info text, when hovering the mouse over those input fields? I dont want to add 3-4 sentences of text to the title of each select/numericInput.
Thanks :)
If you don't mind an extra package dependancy then you can use bsTooltip from the shinyBS package. Note that the hover tooltip sometimes doesn't show up unless you click on the input in the RStudio viewer pane, but if you run your app in your browser, the hover trigger should work:
library(shiny)
library(shinyBS)
ui <- fluidPage(
selectInput("input1", "Select input", c("choice1", "choice2")),
bsTooltip(id = "input1",
title = "Here is some text with your instructions")
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)

R Shiny: Use Onclick Option of Actionbutton on the Server Side

I want to make a Shiny App in which the user can press an actionbutton which would then trigger some code on the server side creating a file in the www folder and then opens/downloads the file.
Suppose the file is test.txt (in my case it would be a variety of R, Excel, and exe files which will be copied from different folders on a drive to the www folder).
My first try was to use the actionbutton with the onclick option as shown below
ui <- fluidPage(
actionButton("showtxt", "Show/Download File", onclick = "window.open('test.txt')")
)
server <- function(input, output, session){
observeEvent(input$showtxt,{
# Write some text
write.table(c("Test"), file = "www/test.txt")
})
}
shinyApp(ui=ui,server=server)
But this doesn't work since the onclick action is done before the observevent is evaluated.
I then tried to call a function inside to the onclick option as shown below
CreateFileAndLink <- function(){
write.table(c("Test"), file = "www/test.txt")
return("window.open('test.txt')")
}
ui <- fluidPage(
actionButton("showtxt", "Show/Download File", onclick = CreateFileAndLink())
)
server <- function(input, output, session){}
shinyApp(ui=ui,server=server)
This works but has the downside that now the file is created when upon opening the Shiny App as opposed to creating the file when the user clicks the actionbutton. This is very inefficient if I were to use this piece of code multiple times in an App with relatively large files.
Maybe it is possible to make sure that the observevent is executed before the onclick-action, or maybe use the onclick option on the server side.
Any help would be greatly appreciated!
Cheers
UPDATE:
I found out that the great shinyjs package by Dean Attali contains a onclick function that might be of help here. I tried to run the code below but it didn't work :/
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
actionButton("showtxt", "Show/Download File")
)
server <- function(input, output, session){
observeEvent(input$showtxt,{
# Write some text
write.table(c("Test"), file = "www/test.txt")
# Call Onclick
onclick("showtxt", "window.open('test.txt')")
})
}
shinyApp(ui=ui,server=server)
I found a solution using the onclick function from the shinyjs package.
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
actionButton("showtxt", "Show/Download File")
)
server <- function(input, output, session){
observeEvent(input$showtxt,{
# Write some text
write.table(c("Test"), file = "www/test.txt")
})
# Call Onclick
onclick("showtxt", runjs("window.open('test.txt')"))
}
shinyApp(ui=ui,server=server)

R Shiny: Is there a way to check if a button is disabled using shinyjs package?

Is there a way to check if a download button is disabled using the shinyjs R package? I want to use shinyjs or something similar because they have very easy syntax. This is my package:
server.R:
library(shiny)
library(shinyjs)
library(shinyBS)
shinyServer(function(input, output) {
observe({
shinyjs::disable("download1")
if(shinyjs::is.disabled("download1")){ ## This is what I am trying to do
# Do something
}
})
})
ui.R
shinyUI(fluidPage(
downloadButton("download1")
))
Not directly (well, not easily*).
Buttons can only be disabled when you decide to disable them, so you can have some sort of a reactive variable that holds whether or not the button should be disabled, and whenever you disable the button, you also change the value of that variable. In order to make sure they stay in sync, every time you want to disable the button you can set the variable to mirror that, and then you can use shinyjs::toggleState(condition = variable) so that the disabled state will mirror what the variable says.
Example code to illustrate what I mean:
library(shiny)
ui <- fluidPage(
shinyjs::useShinyjs(),
numericInput("num", "When divisible by 3, disable the button", 1),
actionButton("btn", "button")
)
server <- function(input, output, session) {
values <- reactiveValues(disable = FALSE)
observe({
values$disable <- (input$num %% 3 == 0)
})
observe({
shinyjs::toggleState("btn", condition = !values$disable)
})
}
shinyApp(ui = ui, server = server)
In this app, whenever you want to disable the button, simply set values$disable to FALSE and to enable the button set it to TRUE. To check if the button is currently on or off at any point in time, you can look at the value of values$disable.
*I'm guessing that you wanted a more direct approach to ask the app a question in real time "hey shiny, is button X currently disabled?". You can do that, but it would involve writing custom javascript code to check for the button state, and for custom code to ask javascript that question and to listen for its response. This would work and be guaranteed to be correct, but it's likely overkill for most cases.

use the same dataTableOutput in different tabs

Is there a possibility to reuse a dataTableOutput in several tabs? The only possibility I found was using a layout where the dataTableOutput gets its own row but I don't want it above all tabs.
If I just call the dataTableOutput multiple times, none of the tables get printed.
EDIT:
Thanks to the answer of daattali I got this almost done. The only thing I didn't mentioned before was, I need the two tables synchronised in a way. At the moment, when I try to update each other via proxy, the whole system gets buggy when selecting to many rows in a short time...
You can't use the same id (since you can't have two elements on the same page with the same id), but what you can do is generate the table once as a reactive value and then simply return that value inside the render table functions. This has the benefit of only running the code for generating the table once, and re-using the table in as many outputs as you want.
Example:
library(shiny)
ui <- fluidPage(
tabsetPanel(
tabPanel("tab1", "tab 1", DT::dataTableOutput("table1")),
tabPanel("tab2", "tab 2", DT::dataTableOutput("table2"))
)
)
server <- function(input, output, session) {
table_data <- reactive({
DT::datatable(iris)
})
output$table1 <- DT::renderDataTable(table_data())
output$table2 <- DT::renderDataTable(table_data())
}
shinyApp(ui = ui, server = server)

Duplicate an icon in shiny actionButton

I would like to add a Font Awesome 'child' icon twice in my actionButton in Shiny. The following app displays the child once:
library(shiny)
ui <- fluidPage(
actionButton("child","children", icon("child"))
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
I tried the obvious to no avail:
actionButton("child","children", icon(c("child","child")))
I must accept this is quite a niche question.
This has nothing to do with the fact that you want the same icon twice. You just can't pass a vector of names into the icon() function. If you look at the documentation of icon() it says it accepts the name of an icon, not a vector for multiple icons.
To do what you want, you can simply add multiple icons in the label. Something like this
actionButton("child", div(icon("child"), icon("child"), "children"))

Resources