Shiny: Show Download Button Only If An Action Button Is Pressed - r

I have a reactive data frame df1(). A user can add their initials as text inputs such that the text is filled to rows as a new column name when the user clicks the Add button.
Everything works fine but I would like to add one more thing:
Make the download button download show only if the action button bttn1 is pressed. Currently download is shown regardless of pressing bttn1.
I can't understand why the following is not working:
observe({
if (is.null(input$bttn1)) {shinyjs::hide("download")}
else {shinyjs::show("download")}
})
The following is a fully working code:
##### ui
ui <- dashboardPage(
skin = "black",
#### Upper navigation bar
dashboardHeader(
title = "title",
titleWidth = 230
),
#### Side bar
dashboardSidebar(disable = T),
#### Body
dashboardBody(
shinyjs::useShinyjs(),
tabsetPanel(
tabPanel(
### tab1
tabName = "tab1",
h5("Tab 1"),
fluidRow(
reactableOutput("table1"),
textInput("textinput1", "Initials:"),
actionButton("bttn1", "Add", class = "btn-primary"),
reactableOutput("table2"),
uiOutput("ui_download")
) # fluidRow
), # tabPanel
#### tab2
tabPanel(
tabName = "tab2",
h5("Tab 2"),
fluidRow(
) # fluidRow
) # tabPanel
) # tabsetPanel
) # dashboardBody
) # dashboardPage
#### server
server <- function(input, output, session) {
## df1
# reactive
df1 <- reactive({
data.frame(
"id" = c("A", "A", "A", "A"),
"num1" = c(10, 11, 12, 13)
)
})
# renderReactable
output$table1 <- renderReactable({
reactable(df1(), borderless = F, defaultColDef = colDef(align = "center"))
})
## df2
## Text input
rv1 <- reactiveValues()
observe({
if (nrow(df1()) == 0) {shinyjs::hide("bttn1")}
else {shinyjs::show("bttn1")}
})
observe({
if (nrow(df1()) == 0) {shinyjs::hide("textinput1")}
else {shinyjs::show("textinput1")}
})
observeEvent(input$bttn1, {
rv1$values <- df1()
rv1$values$name <- input$textinput1
})
rv1_text <- reactive({
rv1$values
})
output$table2 <- renderReactable({
req(rv1_text())
reactable(rv1_text(), borderless = F, defaultColDef = colDef(align = "center"))
})
## downloadButton
# renderUI
output$ui_download <- renderUI({
# req(rv1_text())
downloadButton("download", "Download")
})
**# Why isn't this working?**
observe({
if (is.null(input$bttn1)) {shinyjs::hide("download")}
else {shinyjs::show("download")}
})
# Download csv
output$download <- downloadHandler(
filename = function() {
paste0('data', '.csv')
},
content = function(file) {
write.csv(rv1_text(), file, row.names = F)
}
)
}
shinyApp(ui, server)

I couldn't run your codes since you did not share the libraries you used in. But If I understand you correctly, conditionalPanel is very suitible for your purpose.
Here is a small shiny app that you can adapt it to your codes:
library(shiny)
ui <- fluidPage(
actionButton("call_download", "Show Download Button"),
conditionalPanel(condition = "input.call_download == 1",
downloadLink('downloadData', 'Download')
)
)
server <- function(input, output) {
output$downloadData <- downloadHandler(
filename = function() {
paste('data-', Sys.Date(), '.csv', sep='')
},
content = function(con) {
write.csv(mtcars, con)
} )
}
shinyApp(ui, server)

Related

How to create a button that will create a pdf file of a table

I currently have a table being generated and I would like the user to be able to create a pdf file when they click the download button.
I am currently getting an error where when I click the download button I get an html file that downloads the entire page of the app. I thought that using pdf(file) would work but it ignores the function.
Here is currently what I have.
library(shiny)
library(xlsx)
library(shinyWidgets)
population <- read.xlsx("population.xlsx", 1)
fieldsMandatory <- c("selectedCountry")
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
appCSS <-
".mandatory_star {color: red;}"
ui <- fluidPage(
navbarPage(title = span("Spatial Tracking of COVID-19 using Mathematical Models", style = "color:#000000; font-weight:bold; font-size:15pt"),
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
div(
id = "dashboard",
pickerInput(
inputId = "selectedCountry",
labelMandatory ("Country"),
choices = population$Country,
multiple = FALSE,
options = pickerOptions(
actionsBox = TRUE,
title = "Please select a country")
),
sliderInput(inputId = "agg",
label = "Aggregation Factor",
min = 0, max = 50, step = 5, value = 10),
actionButton("go","Run Simulation"),
)
),
mainPanel(
tabsetPanel(
tabPanel("Input Summary", verbatimTextOutput("summary"),
tableOutput("table"),
downloadButton(outputId = "downloadSummary", label = "Save Summary"))
)
)
)
)
)
)
server <- function(input, output, session){
observeEvent(input$resetAll, {
shinyjs::reset("dashboard")
})
values <- reactiveValues()
values$df <- data.frame(Variable = character(), Value = character())
observeEvent(input$go, {
row1 <- data.frame(Variable = "Country", Value = input$selectedCountry)
row2 <- data.frame(Variable = "Aggregation Factor", Value = input$agg)
values$df <- rbind(row1, row2)
})
output$table <- renderTable(values$df)
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "go", condition = mandatoryFilled)
})
output$downloadSummary <- downloadHandler(
filename = function(file) {
paste('my-report.pdf', )
},
content = function(file) {
pdf(file)
}
)
}
shinyApp(ui,server)
Here's a minimal example:
library(shiny)
ui <- fluidPage(
downloadButton("savepdf", "Save pdf")
)
server <- function(input, output, session) {
output$savepdf <- downloadHandler(
filename = "test.pdf",
content = function(file) {
pdf(file)
plot(iris$Sepal.Length, iris$Sepal.Width)
dev.off()
}
)
}
shinyApp(ui, server)
Also see here.
Here is a minimal example with the package latexpdf. It will create the pdf table in the folder of the app.
library(shiny)
library(latexpdf)
dat <- head(iris, 5)
ui <- fluidPage(
br(),
actionButton("dwnld", "Create pdf"),
tableOutput("mytable")
)
server <- function(input, output, session){
output[["mytable"]] <- renderTable({
dat
})
observeEvent(input[["dwnld"]], {
as.pdf(dat)
})
}
shinyApp(ui, server)

Shiny/R: turn columns into checkbox

I have a beginner problem. I need to turn columns into checkbox. Next, I need to assign integer values ​​to these checkbox (1,2,3) so that they are transported to the function "int<-csv()[,c(5,6,7,8,9,10)]" (where the numeric values ​​are separated by commas). Also, I need that if more than one item is selected, a comma is placed to the right of it. It is possible? Thanks in advance!
This is my code:
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(readxl)
library(tidyverse)
library(readxl)
library(stringr)
# Dashboard
ui <- dashboardPage(
dashboardHeader(
title = "Page"
),
dashboardSidebar(
sidebarMenu(
menuItem(
"Home",
tabName = "home")
)
),
dashboardBody(
tabItems(
# Home
tabItem(
tabName = "home", h2("Hello!"),
br(),
box(
width = 100,
fileInput("file", "Choose the Sheet", accept = c(
".xlsx")),
),
p("Upload Sheet", style="font-weight: bold;"),
box(
width = 200,
tableOutput("content"), style="overflow:
hidden; height: 90px; overflow-y: scroll;
overflow-x: scroll;")
)
),
)
)
# Server
server <- function(input, output, session) {
# Sheet Upload
csv <- reactive({
req(input$file)
inFile <- input$file
df<- read_xlsx(inFile$datapath)
return(df)
})
# Archive Without Extension
output$my_file <- renderText({
# Test if file is selected
if (!is.null(input$file)) {
return(str_replace(input$file$name, '\\.xlsx', ' ') )
} else {
return(NULL)
}
})
# Show Datasheet
output$content <- renderTable({
req(input$file)
inFile <- input$file
read_excel(inFile$datapath, sheet = 1, col_names = TRUE,
col_types = NULL, na = "", skip = 0)
})
output$calfa <-
renderPrint({
int<-csv()[,c(5,6,7,8,9,10)]
names(int)
})
}
# App
shinyApp(ui = ui, server = server)

div in shiny overriding scroll bars for whole app

I am trying to use a package that allows users to graph their data in shiny (esquiss). It works fine. However the user interface for the shiny module in the package requires a fixed height container. I have therefore placed the call to the module in tag$div (inside a modal) called by a button.
The problem is that this call to this module seems to get rid of all the scrollbars for the main page of the app (so I can't scroll to the bottom of the main page (it is a one page app).
How can I limit the html of the module to prevent it from overriding the rest of the app? The code for the module being called is here.
My reproducible example follows:
ui.R
library(shiny)
library(esquisse)
library(shinyBS)
ui <- fluidPage(
dashboardPage(
dashboardHeader(title = ''),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard")
)),
dashboardBody(
actionButton(inputId = "esquissGraphs",label = "esquissGraphs"),
DT::dataTableOutput("mytable"),
bsModal("modalExample", "Data Table", "esquissGraphs", size = "large",
tags$h1("Use esquisse as a Shiny module"),
radioButtons(
inputId = "data",
label = "Data to use:",
choices = c("Mydftbbinnit", "mtcars"),
inline = TRUE
),
tags$div(
style = "height: 700px;", # needs to be in fixed height container
esquisserUI(
id = "esquisse",
header = FALSE, # dont display gadget title
choose_data = FALSE # dont display button to change data
)
)
)
)
)
)
server.R
RV <- reactiveValues(data = data.frame())
RV2 <- reactiveValues(data = data.frame())
server <- function(input, output, session) {
n<-c("1","434","101")
t<-c("Bugs","Mugs","Thugs")
RV$data<-data.frame(n,t,stringsAsFactors = FALSE)
o<-c("1","434","101")
p<-c("Bugs","Mugs","Thugs")
RV2$data<-data.frame(o,p,stringsAsFactors = FALSE)
output$mytable = DT::renderDataTable({
mtcars
})
data_r <-reactiveValues(data = data.frame())
observeEvent(input$data, {
if (input$data == "Mydftbbinnit") {
data_r$data <- RV$data
data_r$name <- "Mydftbbinnit"
} else {
data_r$data <- RV2$data
data_r$name <- "The rest"
}
})
callModule(module = esquisserServer, id = "esquisse", data = data_r)
}
shinyApp(ui, server)
You need to add
tags$style("html, body {overflow: visible !important;")
in your UI to force scrollbar to appear.
Source : https://github.com/dreamRs/esquisse/blob/master/R/esquisserUI.R
Full example gives :
library(shiny)
library(shinydashboard)
library(esquisse)
library(shinyBS)
library(shiny)
library(esquisse)
library(shinyBS)
ui <- fluidPage(
dashboardPage(
dashboardHeader(title = ""),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard")
)
),
dashboardBody(
tags$style("html, body {overflow: visible !important;"),
actionButton(inputId = "esquissGraphs", label = "esquissGraphs"),
DT::dataTableOutput("mytable"),
bsModal("modalExample", "Data Table", "esquissGraphs",
size = "large",
tags$h1("Use esquisse as a Shiny module"),
radioButtons(
inputId = "data",
label = "Data to use:",
choices = c("Mydftbbinnit", "mtcars"),
inline = TRUE
),
tags$div(
style = "height: 700px;", # needs to be in fixed height container
esquisserUI(
id = "esquisse",
header = FALSE, # dont display gadget title
choose_data = FALSE # dont display button to change data
)
)
)
)
)
)
RV <- reactiveValues(data = data.frame())
RV2 <- reactiveValues(data = data.frame())
server <- function(input, output, session) {
n <- c("1", "434", "101")
t <- c("Bugs", "Mugs", "Thugs")
RV$data <- data.frame(n, t, stringsAsFactors = FALSE)
o <- c("1", "434", "101")
p <- c("Bugs", "Mugs", "Thugs")
RV2$data <- data.frame(o, p, stringsAsFactors = FALSE)
output$mytable <- DT::renderDataTable({
mtcars
})
data_r <- reactiveValues(data = data.frame())
observeEvent(input$data, {
if (input$data == "Mydftbbinnit") {
data_r$data <- RV$data
data_r$name <- "Mydftbbinnit"
} else {
data_r$data <- RV2$data
data_r$name <- "The rest"
}
})
callModule(module = esquisserServer, id = "esquisse", data = data_r)
}
shinyApp(ui, server)

How to refresh a shiny datatable with a button that runs a function

I have looked everywhere and cant seem to find help with what must be a common issue.
I have a datatable in a shiny app. I load data into it when it first appears. It consists of one column of text
I want the user be able to press a button that takes the data in the datatable and performs an action on it and then presents a datatable with the result of that function. The function (not shown) basically splits the single column up into several columns.
I cant seem to figure out how to run a function from a button that refreshes and shows the new datatable.
This is what I have so far:
server.R
library(shiny)
library(EndoMineR)
RV <- reactiveValues(data = PathDataFrameFinalColon)
server <- function(input, output) {
output$mytable = DT::renderDT({
RV$data
})
output2$mytable = DT::renderDT({
RV$data<-myCustomFunction(RV$data)
})
}
ui.R
library(shiny)
basicPage(
fluidPage(
DT::dataTableOutput("mytable")
))
basically how do I allow a button on the page to run a specific function that then updates the datatable?
You can use observeEvent() and ignoreInit = TRUE so that the initial dataframe is rendered without the function being applied.
server <- function(input, output) {
RV <- reactiveValues(data = PathDataFrameFinalColon)
output$mytable = DT::renderDT({
RV$data
})
observeEvent(input$my_button,{
RV$data<-myCustomFunction(RV$data)
},ignoreInit = TRUE)
}
ui <- basicPage(
fluidPage(
DT::dataTableOutput("mytable"),
actionButton("my_button",label = "Run Function")
))
I hope this helps you. Have fun;
library(shiny)
library(shinydashboard)
dat = data.frame(id = c("d","a","c","b"), a = c(1,2,3,4), b = c(6,7,8,9))
header <- dashboardHeader(
)
sidebar <- dashboardSidebar(
tags$head(tags$style(HTML('.content-wrapper { height: 1500px !important;}'))),
sidebarMenu (
menuItem("A", tabName = "d1"),
menuItem("B", tabName = "d2"),
menuItem("C", tabName = "d3")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "d1",
box(title = "AAA",
actionButton("refreshTab1_id", "Refresh Tab 1"),
actionButton("sortTable1_id", "Sort Table 1"),
DT::dataTableOutput("table_for_tab_1", width = "100%"))
),
tabItem(tabName = "d2",
box(title = "BBB",
actionButton("refreshTab2_id", "Refresh Tab 2"),
actionButton("sortTable2_id", "Sort Table 2"),
DT::dataTableOutput("table_for_tab_2", width = "100%"))
),
tabItem(tabName = "d3",
box(title = "CCC",
actionButton("refreshTab3_id", "Refresh Tab 3"),
actionButton("sortTable3_id", "Sort Table 3"),
DT::dataTableOutput("table_for_tab_3", width = "100%"))
)
)
)
# UI
ui <- dashboardPage(header, sidebar, body)
# Server
server <- function(input, output, session) {
observe({
if (input$sortTable1_id || input$sortTable2_id || input$sortTable3_id) {
dat_1 = dat %>% dplyr::arrange(id)
} else {
dat_1 = dat
}
output$table_for_tab_1 <- output$table_for_tab_2 <- output$table_for_tab_3 <- DT::renderDataTable({
DT::datatable(dat_1,
filter = 'bottom',
selection = "single",
colnames = c("Id", "A", "B"),
options = list(pageLength = 10,
autoWidth = TRUE#,
# columnDefs = list(list(targets = 9,
# visible = FALSE))
)
)
})
})
observe({
if (input$refreshTab1_id || input$refreshTab2_id || input$refreshTab3_id) {
session$reload()
}
})
}
# Shiny dashboard
shiny::shinyApp(ui, server)

How to share dataframes from an observeEvent module to another

I need to share more than one dataframe within an observeEvent block with other observeEvent blocks. The reason is because the data is built only after a button is pressed.
I found the following two questions very resourceful, but not quite close to the structure of my app ...
How to return a variable from a module to the server in an R Shiny app?
How to access dataframe from another observeEvent?
I tried to wrap the button observeEvent within a module, but then the app does not work. I cannot figure out how to change my code into modules to make it work.
Here is a minimal example.
library(shiny)
library(shinydashboard)
library(DT)
header1 <- dashboardHeader(
title = "My App"
)
sidebar1 <- dashboardSidebar(
sidebarMenu(id = "sbmenu",
menuItemOutput("menuitems01"),
menuItemOutput("menuitems02")
) #sidebarMenu
) #dashboardSidebar
body1 <- dashboardBody(
tabItems(
uiOutput("tabitems01")
) #tabItems
) #dashboardBody
ui <- dashboardPage(header1, sidebar1, body1)
server <- function(input, output, session) {
# render menu
output$menuitems01 <- renderMenu({
menuItem("Main", tabName = "main", icon = icon("key"))
})
# render tabitems
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
observeEvent(input$btn1, {
dfresult02 <- data.frame(c(1, 2), c(3, 4)) # e.g. read some data from db
dfresult05 <- data.frame(c(5, 6), c(7, 8)) # e.g. read some data from db
rResult02 <- reactive({dfresult02}) # NEED TO MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
rResult05 <- reactive({dfresult05}) # NEED TO MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
output$menuitems02 <- renderMenu({
menuItem("MyData", tabName = "mydata", icon = icon("th"))
}) #renderMenu
updateTabItems(session, "sbmenu", "mydata")
print("button1 pressed")
}) #observeEvent(input$btn1)
observeEvent(input$sbmenu, {
# IF I UNCOMMENT THE NEXT FOUR LINES, THE TABLES ARE DISPLAYED
#dfresult02 <- data.frame(c(1, 2), c(3, 4))
#rResult02 <- reactive({dfresult02})
#dfresult05 <- data.frame(c(1, 2), c(3, 4))
#rResult05 <- reactive({dfresult05})
if(input$sbmenu == "mydata")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "mydata",
h2("My Data"),
DT::dataTableOutput('tbl02'),
DT::dataTableOutput('tbl05')
) #tabItem
}) #renderUI
output$tbl02 <- DT::renderDataTable({rResult02()}) # NEED DATA FROM OTHER MODULE HERE
output$tbl05 <- DT::renderDataTable({rResult05()}) # NEED DATA FROM OTHER MODULE HERE
} #if(input$sbmenu == "mydata")
if(input$sbmenu == "main")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
} #if(input$sbmenu == "main")
}) #observeEvent(input$sbmenu)
} #server
shinyApp(ui = ui, server = server)
Using the very useful comment above, I ended up with this code, that works perfectly! Thank you so much!!! (note the use of reactiveValues)
library(shiny)
library(shinydashboard)
library(DT)
header1 <- dashboardHeader(
title = "My App"
)
sidebar1 <- dashboardSidebar(
sidebarMenu(id = "sbmenu",
menuItemOutput("menuitems01"),
menuItemOutput("menuitems02")
) #sidebarMenu
) #dashboardSidebar
body1 <- dashboardBody(
tabItems(
uiOutput("tabitems01")
) #tabItems
) #dashboardBody
ui <- dashboardPage(header1, sidebar1, body1)
server <- function(input, output, session) {
# DECLARE REACTIVEVALUES FUNCTION HERE
rResult <- reactiveValues(df02 = 0, df05 = 0)
# render menu
output$menuitems01 <- renderMenu({
menuItem("Main", tabName = "main", icon = icon("key"))
})
# render tabitems
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
observeEvent(input$btn1, {
dfresult02 <- data.frame(c(1, 2), c(3, 4)) # e.g. read some data from db
dfresult05 <- data.frame(c(5, 6), c(7, 8)) # e.g. read some data from db
rResult$df02 <- dfresult02 # MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
rResult$df05 <- dfresult05 # MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
output$menuitems02 <- renderMenu({
menuItem("MyData", tabName = "mydata", icon = icon("th"))
}) #renderMenu
updateTabItems(session, "sbmenu", "mydata")
print("button1 pressed")
}) #observeEvent(input$btn1)
observeEvent(input$sbmenu, {
if(input$sbmenu == "mydata")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "mydata",
h2("My Data"),
DT::dataTableOutput('tbl02'),
DT::dataTableOutput('tbl05')
) #tabItem
}) #renderUI
output$tbl02 <- DT::renderDataTable(rResult$df02) # GET DATA FROM OTHER MODULE(S) HERE
output$tbl05 <- DT::renderDataTable(rResult$df05) # GET DATA FROM OTHER MODULE(S) HERE
} #if(input$sbmenu == "mydata")
if(input$sbmenu == "main")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
} #if(input$sbmenu == "main")
}) #observeEvent(input$sbmenu)
} #server
shinyApp(ui = ui, server = server)

Resources