I'm working on a quiz type program in Shiny, which needs to have radio buttons that update with answers from a table. I have the code below, but the radio buttons don't update, and the answers remain 2, 3, 4, 5, and 6 despite changing questions. Any ideas on why this might be happening, and what would fix this?
library(shiny)
ui <- fluidPage(
selectInput("numberchoice",label = "Choose an image", choices = c(1:6), selected = 1)
,
imageOutput("image")
,
radioButtons("answerchoice", "Answers", choices = c(2:6))
)
server <- function(input,output,session) {
answers <- read.csv("~/Answers.csv")
questions <- read.csv("~/Answers.csv")
output$image <- renderImage(list(src = paste("~",".png", sep = "")
,contentType = "image/png", alt = "Face"),deleteFile = FALSE)
eventReactive(input$numberchoice,{updateRadioButtons(session,"answerchoice",choices = questions[input$numberchoice,2:6])})
}
shinyApp(ui = ui, server = server)
Try replacing eventReactive with observeEvent. The following code works for me.
library(shiny)
ui <- fluidPage(
selectInput("numberchoice", label = "Choose an image", choices = 1:6, selected = 1),
radioButtons("answerchoice", "Answers", choices = 1:6 )
)
server <- function(input, output, session) {
observeEvent(input$numberchoice,{
updateRadioButtons(session, "answerchoice",
choices = letters[1:input$numberchoice])})
}
shinyApp(ui = ui, server = server)
It seems like eventReactive didn't trigger so updateRadioButtons was not the problem.
Related
I want to be able to update the selection available in the pickerInput based upon the selection made in the radio button input. In the example below, I want the radio button "A", to give a pickerInput list of mtcars$cyl, whilst a picker input of "B" to give a picker input of mtcars$mpg
I have tried doing this using if statements, but I haven't got anywhere so far. Reproducible example below:
library(shiny)
library(leaflet)
library(shinyjs)
library(rgeos)
library(tidyverse)
library(openxlsx)
library(plotly)
library(shinyWidgets)
library(rgdal)
ui <- fluidPage(shinyjs::useShinyjs(),
fluidRow(column(
6,radioButtons("type", "Type:",
c("A" = "norm",
"B" = "unif")))),
fluidRow(column(
3,
pickerInput("regInput","Region",choices=unique(mtcars$cyl),
options = list(`actions-box` = TRUE),multiple = T,
selected = unique(mtcars$cyl)))))
server <- function (input, output, session) {
observeEvent(input$type,{
a_option <- input$regInput
if (a_option == "B") {
updatePickerInput(session = session,inputId = "regInput",
choices =unique(mtcars$mpg))}})
}
shinyApp(ui = ui, server = server)
As said in the other answer you need to observe input$type and update the picker input according to the values in it. Also, it's important to include an else statement, to be able to update the picker input when the user picks between the radio button choices multiple times. Finally, on the updatePickerInput you need to include the selected argument to maintain the behaviour as it is on the ui.
Here's the code doing what I've described above:
library(shiny)
library(shinyjs)
library(tidyverse)
library(shinyWidgets)
ui <- fluidPage(shinyjs::useShinyjs(),
fluidRow(
column(
6,
radioButtons("type",
"Type:",
c("A" = "norm",
"B" = "unif"))
)),
fluidRow(
column(
3,
pickerInput("regInput","Region",
choices=unique(mtcars$cyl),
options = list(`actions-box` = TRUE),
multiple = T,
selected = unique(mtcars$cyl))
))
)
server <- function (input, output, session) {
observeEvent(input$type,{
if (input$type == "unif") {
updatePickerInput(session = session,inputId = "regInput",
choices = unique(mtcars$mpg),
selected = unique(mtcars$mpg))
} else {
updatePickerInput(session = session,inputId = "regInput",
choices = unique(mtcars$cyl),
selected = unique(mtcars$cyl))
}
})
}
shinyApp(ui = ui, server = server)
The server has to listen to the right UI Element (ID = "type" for the radio buttons in question). Currently it observes an undefined element "dist".
Try changing
observeEvent(input$dist, { code })
to
observeEvent(input$type, { code })
I have a selectizeInput with some grouped elements with multiple selection. Is there an elegant way (e.g. using the options argument) of allowing just one element per group, so that a whole group will discarded (or disabled) when an element of this specific group is selected?
So far I tried it programmatically, but than the dropdown menu of the selectizeInput will be closed when updating the selectizeInput.
Minimal example:
library(shiny)
ui <- fluidPage(
selectizeInput("selInput", "Default",
choices=list(g1 = c(A="A",B="B"),
g2 = c(C="C",D="D")),
multiple=T),
selectizeInput("oneElementPerGroup", "One element per group",
choices=list(g1 = c(A="A",B="B"),
g2 = c(C="C",D="D")),
multiple=T)
)
server <- function(session, input, output) {
#Removes the corresponding groups of selected items
observeEvent(input$oneElementPerGroup, ignoreNULL = F, {
plusChoice <- input$oneElementPerGroup
names(plusChoice) <- input$oneElementPerGroup
choices <- list(g1 = c(A="A",B="B"),
g2 = c(C="C",D="D"))
if(any(input$oneElementPerGroup %in% c("A", "B"))){
choices[["g1"]] <- NULL
}
if(any(input$oneElementPerGroup %in% c("C", "D"))){
choices[["g2"]] <- NULL
}
choices$we <- plusChoice
updateSelectizeInput(session,"oneElementPerGroup",
choices = choices,
selected=input$oneElementPerGroup)
})
}
shinyApp(ui = ui, server = server)
You can use pickerInput from {shinyWidgets}. Then we can add a little javascript to do what you want. No server code is needed, very simple. Read more about the data-max-options option: https://developer.snapappointments.com/bootstrap-select/options/.
We need to add the limit to each group, not an overall limit, so we can't add it through the options argument in pickerInput, have to do it in raw HTML or use some js code to inject like what I do.
Be sure your inputId="pick" matches the id in the script #pick. Rename pick to whatever you want.
ui <- fluidPage(
shinyWidgets::pickerInput(
inputId = "pick", label = "Selected",
choices =list(g1 = c(A="A",B="B"), g2 = c(C="C",D="D")),
multiple = TRUE
),
tags$script(
'
$(function(){
$("#pick optgroup").attr("data-max-options", "1");
})
'
)
)
server <- function(input, output, session){}
shinyApp(ui, server)
updates:
If you need to update, we need to run the script again but from server. We can send js by using {shinyjs}. Imagine an observer triggers the update event.
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
shinyWidgets::pickerInput(
inputId = "pick", label = "Selected",
choices =NULL,
multiple = TRUE
)
)
server <- function(input, output, session){
observe({
shinyWidgets::updatePickerInput(session, "pick", choices = list(g1 = c(A="A",B="B"), g2 = c(C="C",D="D")))
observeEvent(once = TRUE, reactiveValuesToList(session$input), {
runjs('$("#pick optgroup").attr("data-max-options", "1");')
}, ignoreInit = TRUE)
})
}
shinyApp(ui, server)
I am trying to reset selectizeInput selections upon actionButton input.
Please see the following code, in which I cannot get the eventReactive to function:
library(shiny)
ui <- fluidPage(
column(width = 4,algin = "center", uiOutput("choose_Number")) ,
br(),
column(width = 4, algin = "center",div(
align = "center", actionButton('delete','Delete Number(s)',style="color: #fff; background-color: #53C1BE")))
)
server <- function(input, output, session) {
output$choose_Number <- renderUI({
selectizeInput("choose_Number", "Select Number", as.list(c(1,2,3,4)),selected = c(''), options=list(create=TRUE,'plugins' = list('remove_button'),
persist = FALSE), multiple = TRUE)
})
##### I am trying to reset the selectizeInput upon input from the Delete button
eventReactive(input$delete, {updateSelectizeInput("choose_Number", "Select Number", as.list(c(1,2,3,4)), selected = c(''),options=list(create=TRUE,'plugins' = list('remove_button'),
persist = FALSE), multiple = TRUE)} )
}
shinyApp(ui, server)
Thank you.
The biggest issue was that the session was missing. You can omit the session argument if you want to but then you need to name all other arguments because session is the first in line. Second issue was that you can set multiple in selectizeInput but not later when using updateSelectizeInput() to change it.
Minor improvements: the manual recommends using character() to deselect the current choice. As mentioned by #YBS you do not provide a reactive value so that observeEvent is the better choice here.
PS: are you sure you want to centre align the columns? It looks strange.
library(shiny)
ui <- fluidPage(
column(width = 4, align = "center", uiOutput("choose_Number")),
br(),
column(width = 4, align = "center", div(
align = "center",
actionButton('delete', 'Delete Number(s)', style="color: #fff; background-color: #53C1BE"))
)
)
server <- function(input, output, session) {
output$choose_Number <- renderUI({
selectizeInput("choose_Number", "Select Number", as.list(c(1,2,3,4)), selected = character(),
options = list(create=TRUE,'plugins' = list('remove_button'), persist = FALSE),
multiple = TRUE)
})
##### I am trying to reset the selectizeInput upon input from the Delete button
observeEvent(input$delete, {
updateSelectizeInput(session, "choose_Number", choices = as.list(1:4),
selected = character(0),
options = list(create=TRUE, 'plugins' = list('remove_button'), persist = FALSE))
})
}
shinyApp(ui, server)
I have a UI that is projectdashboard in R shiny. I want to be able to type in a text/search box and have the data associated with it show up as i type.
server <- function(input, output,session) {
output$ui_names = renderUI({
name_list = mydata()[,"names"]
pickerInput("name", label=h3(" Names:"),
choices = sort(unique(name_list)),options = list("actions-box" = TRUE,"live-search" = TRUE,"none-selected-text"='Select Names'),
selected = NULL,multiple = TRUE)
})
ui <- dashboardPage(
dashboardHeader(title=textOutput("title"),titleWidth = 1500),
dashboardSidebar(
uiOutput("ui_names")
)
shinyApp(ui = ui, server = server)
This however does not give me expected or working results. How can i put a text/searchbar in the dashboard side bar, that will 'live-search' the data i am feeding it.
you can use the following:
sidebarSearchForm(textId = "searchText", buttonId = "searchButton",label = "Search...")
Please check if this meet your requirements
I have a small app like this:
require(shiny)
require(shinyjs)
require(rhandsontable)
shinyApp(ui = fluidPage(useShinyjs(),
div(id = 'div1',
titlePanel("RHOT - Form"),
fluidRow(column(width = 3,selectizeInput("Trialid","What Iteration is this?",choices = c('1','2-3','4-7','8-15'))),
column(width = 3,textInput("Techie_Name","Your Name",value='EE')),
column(width = 3,textInput("lab_id","LAB ID",value='NA')),
column(width = 3,textInput("email","Your Email ID",value='eeshanchatterjee#gmail.com'))
),
h4('Observations:'),
rHandsontableOutput("handsontable_obs"),
actionButton("SaveObs", "Save Observations")
),
shinyjs::hidden(div(id = 'SubmitMsg',
h3("Thanks for submitting the Observations!"),
actionLink('addNextObs',"Add Another Observation"))
)
),
server = function(input, output,session){
output$handsontable_obs = renderRHandsontable({
rhandsontable(data.frame(Obs_itr = c(1:5),
Val1 = rep(0,5),
Val2 = rep(0,5)))
})
observeEvent(input$SaveObs,{
shinyjs::reset("div1")
shinyjs::hide("div1")
shinyjs::show("SubmitMsg")
})
observeEvent(input$addNextObs,{
shinyjs::show("div1")
shinyjs::hide("SubmitMsg")
})
}
)
When I run it, I can edit the input fields as well as the tables. Upon hitting the save button, this div resets (using shinyjs::reset), hides, and a hidden thank you div shows up.
Clicking another action link on the 2nd div brings the original one back on.
Now, ass the input fields are reset to their default values, except the handsontable.
Question is, how do I ensure the handsontable resets to default values along with the other input fields?
Adding a reactiveValue and a bit more detail on the rhandsontable gets the job done, but this may not be very efficient:
shinyApp(ui = fluidPage(useShinyjs(),
div(id = 'div1',
titlePanel("RHOT - Form"),
fluidRow(column(width = 3,selectizeInput("Trialid","What Iteration is this?",choices = c('1','2-3','4-7','8-15'))),
column(width = 3,textInput("Techie_Name","Your Name",value='EE')),
column(width = 3,textInput("lab_id","LAB ID",value='NA')),
column(width = 3,textInput("email","Your Email ID",value='eeshanchatterjee#gmail.com'))
),
h4('Observations:'),
rHandsontableOutput("handsontable_obs"),
actionButton("SaveObs", "Save Observations")
),
shinyjs::hidden(div(id = 'SubmitMsg',
h3("Thanks for submitting the Observations!"),
actionLink('addNextObs',"Add Another Observation"))
)
),
server = function(input, output,session){
vals <- reactiveValues(reset=TRUE)
output$handsontable_obs = renderRHandsontable({
input$addNextObs
if(isolate(vals$reset) | is.null(input$handsontable_obs)) {
isolate(vals$reset <- FALSE)
df <- data.frame(Obs_itr = c(1:5),
Val1 = rep(0,5),
Val2 = rep(0,5))
} else df <- hot_to_r(input$handsontable_obs)
rhandsontable(df)
})
observeEvent(input$SaveObs,{
shinyjs::reset("div1")
shinyjs::hide("div1")
shinyjs::show("SubmitMsg")
vals$reset <- TRUE
})
observeEvent(input$addNextObs,{
shinyjs::show("div1")
shinyjs::hide("SubmitMsg")
})
}
)