I have a simple shiny app which I would like to show a warning if user input is bigger than a threshold.
library(shiny)
library(shinyalert)
ui <- fluidPage(
numericInput("obs", "Observations:", 1),
verbatimTextOutput("value")
)
server <- function(input, output) {
observeEvent(input$obs,{
if(!is.na(input$obs) && input$obs >10){
shinyalert("warning!", "input too big", type = "warning")
}
})
output$value <- renderText({ input$obs })
}
shinyApp(ui, server)
if user is not quick enough to provide input, let say for the input$obs = 110 we have 1 second delay between putting the second and third value the popups warning will appear !
How should I fix this ?
Use shinyCatch from spsComps to make your life easier
library(shiny)
library(spsComps)
ui <- fluidPage(
numericInput("obs", "Observations:", 1),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderText({
shinyCatch({
if(!is.na(input$obs) && input$obs >10) warning("input too big")
}, blocking_level = "warning", prefix = "")
input$obs
})
}
shinyApp(ui, server)
when blocking_level = "warning" is specified shinyCatch blocks following code in the renderText expression. So when your number is larger than 10, the new input$obs will not be rendered.
Here's what users see
Here's what developers see in the console
You can use showNotification() from shiny itself:
library(shiny)
ui <- fluidPage(
numericInput("obs", "Observations:", 1),
verbatimTextOutput("value")
)
server <- function(input, output) {
observeEvent(input$obs,{
if(!is.na(input$obs) && input$obs >10){
showNotification(
ui = tags$h4("Input Too Big!"),
type = "warning"
)
}
})
output$value <- renderText({ input$obs })
}
shinyApp(ui, server)
Or {shinytoastr}:
library(shiny)
library(shinytoastr)
ui <- fluidPage(
shinytoastr::useToastr(),
numericInput("obs", "Observations:", 1),
verbatimTextOutput("value")
)
server <- function(input, output) {
observeEvent(input$obs,{
if(!is.na(input$obs) && input$obs >10){
shinytoastr::toastr_warning(
message = "Decrease it.",
title = "Input too big!"
)
}
})
output$value <- renderText({ input$obs })
}
shinyApp(ui, server)
Or {spsComps} as #lz100 mentioned. The choice is yours.
Related
I am trying to alternate the presence of a TinyMCE editor in R Shiny.
I can load the editor, then remove it with the respective actionButtons. However, upon attempting to load it more than once, only a textAreaInput-type interface is rendered:
library(shiny)
library(ShinyEditor)
ui <- fluidPage(
use_editor("API-KEY"),
uiOutput("tiny"),
actionButton("load", "Load TinyMCE"),
actionButton( "remove", "Remove TinyMCE" ))
server <- function(input, output, session) {
observeEvent(input$load, {
output$tiny = renderUI( editor('textcontent'))})
observeEvent(input$remove, {
output$tiny = renderUI( NULL)})
}
shinyApp(ui = ui, server = server)
How would it be possible to reload it? Thank you.
I would try that:
library(shiny)
library(ShinyEditor)
ui <- fluidPage(
use_editor("API-KEY"),
uiOutput("tiny"),
actionButton("btn", "Load/Remove TinyMCE"),
)
server <- function(input, output, session) {
output$tiny <- renderUI({
if(input$btn %% 2 == 0) {
editor('textcontent')
} else {
NULL
}
})
}
shinyApp(ui = ui, server = server)
And if that doesn't work I would hide it instead of removing it:
library(shiny)
library(ShinyEditor)
ui <- fluidPage(
use_editor("API-KEY"),
conditionalPanel(
condition = "input.btn %% 2 == 0",
uiOutput("tiny")
),
actionButton("btn", "Load/Remove TinyMCE"),
)
server <- function(input, output, session) {
output$tiny <- renderUI({
editor('textcontent')
})
}
shinyApp(ui = ui, server = server)
The following is based on #Stéphane Laurent's advice.
library(shiny)
library(ShinyEditor)
library(shinyjs)
ui <- fluidPage(
use_editor("API-KEY"),
useShinyjs(),
uiOutput("tiny"),
actionButton( "toggle", "Toggle TinyMCE" ))
server <- function(input, output, session) {
output$tiny = renderUI( editor('textcontent'))
observe({if(input$toggle %% 2 == 0) {
hide('tiny')
} else {
show('tiny')
}
})
}
shinyApp(ui = ui, server = server)
I have a small Shiny app to randomize speaker's list using insertUI (in case there is be more of them).
The problem is that I only got it working using textInput and I fail to get it done without the input box - just to display the text without the box.
It's more of an aesthetics thing but after many hours of unsuccessful trials I'm reaching out for help here.
I really appreciate your help.
Herunia
Here is the code:
if (interactive()) {
ui <- fluidPage(
actionButton("add", "Next speaker")
)
# Server logic
server <- function(input, output, session) {
a <- sample(c("Speaker 1","Speaker 2","Speaker 3","Speaker 4","Speaker 5"))
uiCount = reactiveVal(0)
observeEvent(input$add, {
uiCount(uiCount()+1)
insertUI(
selector = "#add",
where = "afterEnd",
ui = textInput(paste0("txt", input$add), paste0("Speaker #", uiCount() , ": "),
placeholder = a[uiCount()] ),
)
})
}
shinyApp(ui, server)
}
Is this closer to what you want?
ui <- fluidPage(
actionButton("add", "Next speaker"),
uiOutput("txt")
)
server <- function(input, output, session) {
a <- sample(c("Speaker 1","Speaker 2","Speaker 3","Speaker 4","Speaker 5"))
uiCount = reactiveVal(0)
observeEvent(input$add, {
uiCount(uiCount()+1)
output$txt <- renderUI({
div(
p(
paste0("Speaker #", uiCount(), " :", a[uiCount()])
) #close p
) #close div
})
})
}
shinyApp(ui, server)
Is it possible to get some R object used in Shiny?
For example, in the following code, I want to get text string inputted by users.
However, the .Last.value dose not the desired text string.
ref
How to store the returned value from a Shiny module in reactiveValues?
Ex code
returnUI = function(id) {
ns <- NS(id)
tagList(
textInput(ns("txt"), "Write something")
)
}
returnServer = function(input, output, session) {
myreturn <- reactiveValues()
observe({ myreturn$txt <- input$txt })
return(myreturn)
}
library(shiny)
source("modules/module_1.R")
ui <- fluidPage(
returnUI("returntxt"),
textOutput("mytxt")
)
server <- function(input, output, session) {
myvals <- reactiveValues(
txt = NULL
)
mytxt <- callModule(returnServer, "returntxt")
observe({
myvals$txt <- mytxt$txt
print(myvals$txt)
})
output$mytxt <- renderText({ myvals$txt })
}
shinyApp(ui, server)
.Last.value
Yes, you can push variables to the global environment (your usual workspace) from a Shiny app running in your console:
library(shiny)
ui <- fluidPage(
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
mainPanel(NULL)
)
)
server <- function(input, output) {
observe({
my_global_env <- globalenv()
my_global_env$x <- input$bins
})
}
shinyApp(ui = ui, server = server)
I'd like to run the action button automatically when users open/land on 'tab1'. Therefore, instead of clicking the Refresh button to view the date, I'd like to have the date printed automatically. Is there a way to do this? My real code is more complicated that this simple example. However, it demonstrates what I'd like to do. Thank you!
library(shiny)
ui <- fluidPage(
shiny::tabPanel(value = 'tab1', title = 'Data page',
br(),
shiny::actionButton("btn", "Refresh!"),
br(),
shiny::verbatimTextOutput("out")
)
)
server <- function(input, output, session) {
curr_date <- shiny::eventReactive(input$btn, {
format(Sys.Date(), "%c")
})
output$out <- shiny::renderText({
print(curr_date())
})
}
shinyApp(ui, server)
You can make curr_date reactive to the tabset:
library(shiny)
ui <- fluidPage(
tabsetPanel(
tabPanel(value = 'tab1', title = 'Data page',
br(),
actionButton("btn", "Refresh!"),
br(),
verbatimTextOutput("out")
),
tabPanel(value = 'tab2', title = 'Other tab'),
id = "tabset"
)
)
server <- function(input, output, session) {
curr_date <- eventReactive(list(input$btn, input$tabset), {
req(input$tabset == 'tab1')
format(Sys.time(), "%c")
})
output$out <- renderText({
print(curr_date())
})
}
shinyApp(ui, server)
You should use reactiveValues() and observeEvent() for this. Inside server function:
server <- function(input, output, session) {
text_out <- reactiveValues(date = format(Sys.Date(), "%c"))
observeEvent(input$btn, {
text_out$date <- "something else"
})
output$out <- renderText({
print(text_out$date)
}
I understand that I can use debounce with reactive() like this, and this is the sort of behaviour I need, but I want to use reactiveValues() instead.
ui <- fluidPage(
textInput(inputId = "text",
label = "To see how quickly..."),
textOutput(outputId = "text")
)
server <- function(input, output, session) {
text_input <- reactive({
input$text
})
debounce(text_input, 2000)
output$text <- renderText({
text_input()
})
}
shinyApp(ui, server)
}
But I would prefer to use reactiveValues() rather than reactive().
Is there any way to use debounce with reactiveValues()?
This does not work:
ui <- fluidPage(
textInput(inputId = "text",
label = "To see how quickly..."),
textOutput(outputId = "text")
)
server <- function(input, output, session) {
values <- reactiveValues()
observe({
values$text= function(x)input$text
values$t <-
debounce(values$text(),2000)
})
output$text <- renderText({
values$t()
})
}
shinyApp(ui, server)
I get an error Warning: Error in r: could not find function "r", I guess because values is not a reactive expression?
observe isn't needed:
library(shiny)
ui <- fluidPage(
textInput(inputId = "text", label = "To see how quickly..."),
textOutput(outputId = "text")
)
server <- function(input, output, session) {
values <- reactiveValues()
values$t <- debounce(reactive({input$text}), 2000)
output$text <- renderText({
values$t()
})
}
shinyApp(ui, server)
Or without reactiveValues:
library(shiny)
ui <- fluidPage(
textInput(inputId = "text", label = "To see how quickly..."),
textOutput(outputId = "text")
)
server <- function(input, output, session) {
debouncedText <- debounce(reactive({input$text}), 2000)
output$text <- renderText({
debouncedText()
})
}
shinyApp(ui, server)