I would like to have a button (say A) in sidebarPanel such that after using it another button (say B) will be activated (by renderUI), but the button A will disappear. How can I do this
Here my naive solution. I do not know how to avoid referring button status to itself:
library(shiny)
runApp(list(
ui = fluidPage(
uiOutput("answer"),
uiOutput("part2")
),
server = function(input, output) {
output$answer <- renderUI({
if(input$continue == 0){
checkboxGroupInput(inputId = "firstQ", label = "First question", choices = c("Ans. A" = "a", "Ans. B" = "b"))
actionButton("continue", "Continue")}
})
output$part2 <- renderUI({
if(input$kontynuuj > 0)
actionButton("newButton", "New button")
})
}
))
I think that conditionalPanel in your ui is what you need to use here. It will let you set a condition that determines if part of the UI is shown or not.
In the code below I moved the checkboxGroupInput and the first actionButton to the ui, and left the second actionButton as a renderUI. conditionalPanel will work either way.
Each conditionalPanel evaluates the "Continue" button, the first displays before it has been pressed, the second afterwards.
It is important to note that the condition must be written in javascript, not R. See ?conditionalPanel for the details.
library(shiny)
runApp(list(
ui = fluidPage(
conditionalPanel(condition="input.continue==0",
checkboxGroupInput(inputId = "firstQ", label = "First question",
choices = c("Ans. A" = "a", "Ans. B" = "b")),
actionButton("continue", "Continue")
),
conditionalPanel(condition="input.continue>0",
uiOutput("part2")
)
),
server = function(input, output) {
output$part2 <- renderUI({
actionButton("newButton", "New button")
})
}
))
Related
I'm trying to get the textInput from the user and upon submitting it through an action button,I need to update the choices (Append the user input to already existing radio buttons) ,I tried couple of ways but no luck, Thanks in advance for your Help:)
library(shiny)
ui = navbarPage("Sample Trial",
tabPanel("Input Tab",
mainPanel(
textInput("textinp","Create New Label", placeholder = NULL),
actionButton("labbutton","Create")
)
),
tabPanel("Radio Button Panel",
radioButtons("labradio", label = "New Label",choices=values)
)
)
values <- c("Label1","label2","label3")
server = function(input, output) {
observeEvent(input$labbutton,{
req(input$textinp)
value01 <-input$textinp
updatedValues <- c(values, value01)
updateRadioButtons(session,inputId ="labradio",choices=updatedValues)
})
}#Server End
Currently the App will append user input at first time to the list of already present inputs but upon the second input from the user ,It rewrites the previous one.
Try this
library(shiny)
ui = navbarPage("Sample Trial",
tabPanel("Input Tab",
mainPanel(
textInput("textinp","Create New Label", placeholder = NULL),
actionButton("labbutton","Create")
)
),
tabPanel("Radio Button Panel",
radioButtons("labradio", label = "New Label",choices=values)
)
)
server = function(input, output,session) {
value <- c("Label1","label2","label3")
rv <- reactiveValues(values=value)
observeEvent(input$labbutton,{
req(input$textinp)
rv$values <- c(rv$values, input$textinp)
updateRadioButtons(session,inputId ="labradio",choices=rv$values)
})
}
shinyApp(ui, server)
I want to use bsModal that contains inputs that are generated via renderUI. The inputs depend on my data but will not change after start-up. When opening the modal I want to update the selected values of the input. The problem is that in my minimal reproducible example the first update goes wrong as the inputs inside the modal have not been rendered, yet. From the second update on everything works fine.
Here is the example:
library(shiny)
library(shinyBS)
ui <- fluidPage(
titlePanel("Modal Update Problem"),
actionButton(inputId = "btn_test", label = "Click Me"),
bsModal("modal_test", "Test Modal", "btn_test", size = "large",
uiOutput("test_ui")
)
)
server <- function(input, output, session) {
observeEvent(input$btn_test, {
updateSelectInput(
session = session,
inputId = "test_select",
selected = "B"
)
})
output$test_ui <- renderUI({
selectInput(
inputId = "test_select",
label = "Test",
choices = c("A", "B", "C"),
selected = "A"
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Expected behaviour: Select-Input inside the modal shows "B" every time I click the button.
Current behaviour: It shows "A" (i.e. the initial value) after the first click and "B" after the second click.
Is there a clean solution to do this or at least a workaround? How can I render the UI inside the modal on start-up?
Just using selectInput inside observeEvent displays your expected behavior as shown below. Does your use case require you to use updateSelectInput? If so, you can use outputOptions as shown below.
ui <- fluidPage(
titlePanel("Modal Update Problem"),
actionButton(inputId = "btn_test", label = "Click Me"),
bsModal("modal_test", "Test Modal", "btn_test", size = "large",
uiOutput("test_ui")
)
)
server <- function(input, output, session) {
observeEvent(input$btn_test, {
updateSelectInput(
session = session,
inputId = "test_select",
selected = "B"
)
})
output$test_ui <- renderUI({
selectInput(
inputId = "test_select",
label = "Test",
choices = c("A", "B", "C") ,
selected = "A"
)
})
outputOptions(output, "test_ui", suspendWhenHidden = FALSE)
}
# Run the application
shinyApp(ui = ui, server = server)
writing with a shiny question. I have a navbarPage, id = "navbar", and in the navbarMenu user can select one among several tabPanels. Each tabPanel is assigned a value (value = 1, value = 2, etc). So input$navbar is reactive value with the value of the selected tabPanel.
I have a reactive expression defined which reacts to the changing of the tabPanel (reacts based on input$navbar). What I actually want is for this to react to navigating to a particular tabPanel, but not navigating away from that tabPanel. So, when input$navbar changes from 1 to 2 I want a reaction, but when changing from 2 to 1 no reaction. How can I achieve this?
Here is relevant snippet of my code, I don't think I need a full reproducible example for this but let me know if I'm wrong.
#ui snippet
navbarPage(id = "navbar",
navbarMenu(title = "Title",
tabPanel(title = "tp1", value = 1),
tabPanel(title = "tp2", value = 2),
#more tabPanels and ui stuff...
#server snippet
rctvfx <- reactive({
#want this to react only when input$navbar changes from ==1 to ==2
input$navbar
isolate({
#do stuff
})
})
You can use an if statement. This makes sure the code only runs if the user navigated to the corresponding tab.
library(shiny)
shinyApp(
ui = navbarPage(
"App Title",
id = "navbar",
tabPanel("Plot"),
navbarMenu(
"More",
tabPanel("Summary"),
"----",
"Section header",
tabPanel("Table")
)
),
server = function(input, output){
observe({
if (req(input$navbar) == "Table")
message("Table has been selected")
if (req(input$navbar) == "Plot")
message("Plot has been selected")
})
}
)
I would recomment do use observe rather than reactive to make sure everything runs even if all observers for the reactive are idle.
Another example of the same answer as above
library(shiny)
shinyApp(
ui = navbarPage(
"App Title",
id = "navbar",
tabPanel("Plot"),
navbarMenu(
"More",
tabPanel("Summary"),
tabPanel("Table"),
mainPanel(dataTableOutput("d"))
)
),
server = function(input, output){
output$d = renderDataTable({
if ((input$navbar) == "Table") {
head(mtcars)
} else {
((input$navbar) == "Plot")
head(iris)
}
})
}
)
I built a R Shiny application with multiple tabs, which have some filters in common. Right now, all filters are stand-alone and do not synchronize across multiple tabs. Hence, when I change selectInput1 from value "a" to value "b", I have to repeat this handling on the next tab which contains selectInput2 with the same options/meaning.
I thought about making the filters dynamic, hence rendering them using the server side of R Shiny. Then of course, I can always make selectInput2 equal to selectInput1. But what if the user changes selectInput2 rather than selectInput1? It creates kind of a loop in the logic.
I spent quite some time finding a solution for this problem, and somehow I'm sure I'm not the first one encountering this problem. Suggestions or useful links would be really helpful!
Example:
## UI.R
shinyUI(
dashboardPage("Dashboard",
# Create tabs
tabPanel("Start",
p("This is the frontpage")
),
tabPanel("tab1",
uiOutput("selectInput1")
),
tabPanel("tab2",
uiOutput("selectInput2")
)
)
)
and:
## Server.R
library(shiny)
shinyServer(function(input, output,session){
output$selectInput1 <- renderUI({
selectInput(inputId = "id1",
label = "select",
choices = c("a","b","c"),
selected = "a")
})
output$selectInput2 <- renderUI({
selectInput(inputId = "id2",
label = "select",
choices = c("a","b","c"),
selected = "a")
})
})
I would personally use a single input control to control the different tab panels. One way is to include that single input under your tabs:
shinyApp(
fluidPage(
fluidRow(
tabsetPanel(
tabPanel("Tab1",
verbatimTextOutput("choice1")),
tabPanel("Tab2",
verbatimTextOutput("choice2"))
)
),
fluidRow(
selectInput("id1", "Pick something",
choices = c("a","b","c"),
selected = "a")
)
),
function(input, output, session){
output$choice1 <- renderPrint(input$id1)
output$choice2 <- renderPrint({
paste("The choice is:", input$id1)
})
}
)
Or, as you use a shinydashboard, you could actually add that control in the sidebar, possibly again in its own row under a set of tabs if you must.
I can't think of a reason to have multiple inputs who automatigically select the same thing. Other than slowing down your app, I can't see any gain. But if you insist, you make the selected choice a reactive value using reactiveVal and you use eg observeEvent() to update that reactive value. A small example using shinydashboard:
library(shinydashboard)
library(shiny)
ui <- shinyUI(
dashboardPage(title = "Dashboard",
dashboardHeader(),
dashboardSidebar(
tabsetPanel(
tabPanel("tab1",
uiOutput("selectInput1")
),
tabPanel("tab2",
uiOutput("selectInput2")
)
)),
dashboardBody(
verbatimTextOutput("selected")
)
)
)
server <- shinyServer(function(input, output,session){
thechoice <- reactiveVal("a")
output$selectInput1 <- renderUI({
selectInput(inputId = "id1",
label = "select",
choices = c("a","b","c"),
selected = thechoice())
})
output$selectInput2 <- renderUI({
selectInput(inputId = "id2",
label = "select",
choices = c("a","b","c"),
selected = thechoice())
})
observeEvent(input$id2,{
thechoice(input$id2)
})
observeEvent(input$id1,{
thechoice(input$id1)
})
output$selected <- renderPrint({
c(input$id1, input$id2)
})
})
shinyApp(ui, server)
I would like to implement a 'Reset inputs' button in my shiny app.
Here is an example with just two inputs where I'm using the update functions to set the values back to the default values:
library(shiny)
runApp(list(
ui = pageWithSidebar(
headerPanel("'Reset inputs' button example"),
sidebarPanel(
numericInput("mynumber", "Enter a number", 20),
textInput("mytext", "Enter a text", "test"),
tags$hr(),
actionButton("reset_input", "Reset inputs")
),
mainPanel(
h4("Summary"),
verbatimTextOutput("summary")
)
),
server = function(input, output, session) {
output$summary <- renderText({
return(paste(input$mytext, input$mynumber))
})
observe({
input$reset_input
updateNumericInput(session, "mynumber", value = 20)
updateTextInput(session, "mytext", value = "test")
})
}
))
What I would like to know is if there is also a function that sets back everything to default? That would be useful in case of multiple inputs.
Additionally, I'm not sure if my use of the observe function in order to detect when the action button was hit is the 'proper way' of handling the action buttons?
First of all, your use of the observer is correct, but there is another way that's slightly nicer. Instead of
observe({
input$reset_input
updateNumericInput(session, "mynumber", value = 20)
updateTextInput(session, "mytext", value = "test")
})
You can change it to
observeEvent(input$reset_input, {
updateNumericInput(session, "mynumber", value = 20)
updateTextInput(session, "mytext", value = "test")
})
Also note that you don't need to explicitly "return" from a renderText function, the last statement will automatically be used.
Regarding the main question: Matthew's solution is great, but there's also a way to achieve what you want without having to move all your UI into the server. I think it's better practice to keep your UI in the UI file just because separation of structure and logic is generally a good idea.
Full disclaimer: my solution involves using a package that I wrote. My package shinyjs has a reset function that allows you to reset an input or an HTML section back to its original value. Here is how to tweak your original code to your desired behaviour in a way that will scale to any number of inputs without having to add any code. All I had to do is add a call to useShinyjs() in the UI, add an "id" attribute to the form, and call reset(id) on the form.
library(shiny)
runApp(list(
ui = pageWithSidebar(
headerPanel("'Reset inputs' button example"),
sidebarPanel(
shinyjs::useShinyjs(),
id = "side-panel",
numericInput("mynumber", "Enter a number", 20),
textInput("mytext", "Enter a text", "test"),
tags$hr(),
actionButton("reset_input", "Reset inputs")
),
mainPanel(
h4("Summary"),
verbatimTextOutput("summary")
)
),
server = function(input, output, session) {
output$summary <- renderText({
return(paste(input$mytext, input$mynumber))
})
observeEvent(input$reset_input, {
shinyjs::reset("side-panel")
})
}
))
There isn't such a function in shiny, however, here's a way to accomplish this without having to essentially define your inputs twice. The trick is to use uiOutput and wrap the inputs you want to reset in a div whose id changes to something new each time the reset button is pressed.
library(shiny)
runApp(list(
ui = pageWithSidebar(
headerPanel("'Reset inputs' button example"),
sidebarPanel(
uiOutput('resetable_input'),
tags$hr(),
actionButton("reset_input", "Reset inputs")
),
mainPanel(
h4("Summary"),
verbatimTextOutput("summary")
)
),
server = function(input, output, session) {
output$summary <- renderText({
return(paste(input$mytext, input$mynumber))
})
output$resetable_input <- renderUI({
times <- input$reset_input
div(id=letters[(times %% length(letters)) + 1],
numericInput("mynumber", "Enter a number", 20),
textInput("mytext", "Enter a text", "test"))
})
}
))
Here is yet another option that works for either static or dynamic inputs, and doesn't involve re-rendering inputs entirely.
It uses:
reactiveValuesToList to get all initial input values, and (optionally) any dynamic input values that get initialized afterward.
session$sendInputMessage to update values for generic inputs. The updateXyzInput functions call this under the hood like session$sendInputMessage(inputId, list(value = x, ...).
Every Shiny input uses value for its input message, and almost all will update with their input value as-is. Only a two inputs I've found need special casing - checkboxGroupInput to not send NULL when nothing is checked, and dateRangeInput to convert its c(start, end) to a list(start = start, end = end).
It may not be a good idea to blindly reset ALL inputs (even tabs will be reset), but this can easily be adapted to reset a filtered set of inputs.
library(shiny)
ui <- pageWithSidebar(
headerPanel("'Reset inputs' button example"),
sidebarPanel(
numericInput("mynumber", "Enter a number", 20),
textInput("mytext", "Enter text", "test"),
textAreaInput("mytextarea", "Enter text", "test"),
passwordInput("mypassword", "Enter a password", "password"),
checkboxInput("mycheckbox", "Check"),
checkboxGroupInput("mycheckboxgroup", "Choose a number", choices = c(1, 2, 3)),
radioButtons("myradio", "Select a number", c(1, 2, 3)),
sliderInput("myslider", "Select a number", 1, 5, c(1,2)),
uiOutput("myselUI"),
uiOutput("mydateUI"),
tags$hr(),
actionButton("reset_input", "Reset inputs")
),
mainPanel(
h4("Summary"),
verbatimTextOutput("summary")
)
)
server <- function(input, output, session) {
initialInputs <- isolate(reactiveValuesToList(input))
observe({
# OPTIONAL - save initial values of dynamic inputs
inputValues <- reactiveValuesToList(input)
initialInputs <<- utils::modifyList(inputValues, initialInputs)
})
observeEvent(input$reset_input, {
for (id in names(initialInputs)) {
value <- initialInputs[[id]]
# For empty checkboxGroupInputs
if (is.null(value)) value <- ""
session$sendInputMessage(id, list(value = value))
}
})
output$myselUI <- renderUI({
selectInput("mysel", "Select a number", c(1, 2, 3))
})
output$mydateUI <- renderUI({
dateInput("mydate", "Enter a date")
})
output$summary <- renderText({
return(paste(input$mytext, input$mynumber))
})
}
shinyApp(ui, server)
You can also create a reset button by assigning NULL to your reactive values object.
See this RStudio Shiny article on Using Action Buttons: http://shiny.rstudio.com/articles/action-buttons.html. Specifically, read the sections titled Pattern 4 - Reset buttons and Pattern 5 - Reset on tab change. Examples (including code) are provided in the article.
The article provides solutions that don't require additional packages if that's a concern.