I want to update the choices-argument from a radioButtons-widget in R/shiny. When a user selected a choice, the choices argument should be updated based on the first choice of the user. I mocked this with 4 random letters with the sample-function. It appears that the update does not stop and is updated several times. How do I prevent the behavior of updating multiple times?
Here is code to reproduce my approach:
library("shiny")
ui <- fluidPage(
radioButtons("answerchoice", label = "item", choices = sample(letters, 4), selected = NULL,
)
)
server <- function(input, output, session) {
observeEvent(input$answerchoice,{
updateRadioButtons(
session = session,
inputId = "answerchoice",
choices = sample(letters, 4)
)
})
}
shinyApp(ui = ui, server = server)
Seems like the default setting of selected = NULL might be the problem. radioButton is picking one value initally. This may cause the multiple updates. By setting selected to nothing. The app is not updating uncontrollably.
library("shiny")
ui <- fluidPage(
radioButtons("answerchoice",
label = "item",
choices = sample(letters, 4),
selected = character(0)
)
)
server <- function(input, output, session) {
observeEvent(input$answerchoice,{
updateRadioButtons(
session = session,
inputId = "answerchoice",
choices = sample(letters, 4),
selected = character(0)
)
})
}
shinyApp(ui = ui, server = server)
Related
I would like to update the choices of a pickerInput according to what the user starts typing. Similar to what happens when you start typing with Google.
The suggestions have to be handled serverside.
Below is my code. The problem is that what the user is typing - if it's not an existing choice - is not sent to the server. Is there a way to send what the user types?
Maybe pickerInput is not the right approach? How else could I accomplish this?
library(shiny)
library(shinyWidgets)
suggest <- function(x) {
# would in reality send whatever the user starts typing to an API that returns suggestions
choices <- c("Some", "One", "Suggests", "This", "According", "To", "Input")
choices[grep(x, choices, ignore.case = T)]
}
ui <- fluidPage(
pickerInput(inputId = "id1",
choices = c(),
options = list(`live-search` = T))
)
server <- function(input, output, session) {
observe({
req(input$one)
updatePickerInput(session, inputId = "id1", choices = suggest())
})
}
shinyApp(ui, server)
You can use shiny::selectizeInput() to achieve what you want:
library(shiny)
# Generate arbitrarily thousands of choices which can only be rendered
# serverside to avoid app slowdown:
k <- expand.grid(col1 = letters, col2 = letters, col3 = LETTERS)
choices <- with(k, paste0(col1, col2, col3))
ui <- fluidPage(
selectizeInput(
inputId = "selector",
label = "Selector",
choices = NULL
)
)
server <- function(input, output, session) {
observe({
updateSelectizeInput(
session = session,
inputId = "selector",
choices = choices,
server = TRUE
)
})
}
shinyApp(ui, server)
Created on 2022-07-23 by the reprex package (v2.0.1)
I have the following app which allows for text to be entered and it is then saved as VALUE and printed on a panel.
Although it looks like I can only do this with one text input at a time - even if I click add (so I don't believe this button is working). On top of that I would like for the user to be able to add multiple inputs (like I have below).
And then my VALUE function should be list with multiple inputs.
code below
library(shiny)
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
# selectInput("options", "options", choices=c('abc','def')),
textInput("textbox", "Enter R Package Name", ""),
actionButton("add","Add")
),
mainPanel(
textOutput("caption")
)
)
server <- function(input, output, session) {
observe({
VALUE <- ''
if(input$add>0) {
isolate({
VALUE <- input$textbox
})
}
updateTextInput(session, inputId = "textbox", value = VALUE)
})
output$caption <- renderText({
input$textbox
})
}
shinyApp(ui = ui, server = server)
Have you considered using selectizeInput with it's create option?
library(shiny)
packagesDF <- as.data.frame(installed.packages())
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
selectizeInput(
inputId = "selectedPackages",
label = "Enter R Package Name",
choices = packagesDF$Package,
selected = NULL,
multiple = TRUE,
width = "100%",
options = list(
'plugins' = list('remove_button'),
'create' = TRUE,
'persist' = TRUE
)
)
),
mainPanel(textOutput("caption"))
)
server <- function(input, output, session) {
output$caption <- renderText({
paste0(input$selectedPackages, collapse = ", ")
})
}
shinyApp(ui = ui, server = server)
Does anyone know of a way to use shinyWidgets::pickerInput() with a large number of choices, but speed up the rendering? (similar to server-side selectize using updateSelectizeInput())
What I'm ultimately trying to do: have a shinyWidgets pickerInput() with a large number of choices (~1M).
The problem: it takes a really long time for the app to load with that many choices.
I know that one workaround is to use the shiny::selectizeInput() UI element, because there is a neat way to do a server-side shiny::updateSelectInput(), which makes both the loading of the initial UI element and the subsequent update with a bunch of options run pretty quickly (as described in this article).
However, I really like the formatting options and flexibility that shinyWidgets::pickerInput() offers.
Examples:
This works and loads quickly, but uses shiny::selectizeInput() instead of shinyWidgets::pickerInput(), which I want to use.
library(shiny)
ui = shiny::fluidPage(
shiny::uiOutput(outputId = "ui_output")
)
server = function(input, output) {
output$ui_output = shiny::renderUI({
shiny::selectizeInput(
inputId = "select",
label = "Select:",
choices = NULL
)
})
shiny::observe({
shiny::updateSelectizeInput(
inputId = "select",
choices = 1:1000000,
selected = 1,
server = TRUE
)
})
}
shiny::shinyApp(ui, server)
When trying to do the same with shinyWidgets::pickerInput(), I tried both loading the choices directly into the UI initially:
server = function(input, output) {
output$ui_output = shiny::renderUI({
shinyWidgets::pickerInput(
inputId = "select",
label = "Select:",
choices = 1:1000000
)
})
}
And also trying to same logic that I used in the first example, which is to initially load the UI object with choices = NULL, and then have a shiny::observe() call that updates the UI element's choices (this works, but is really slow):
server = function(input, output) {
output$ui_output = shiny::renderUI({
shinyWidgets::pickerInput(
inputId = "select",
label = "Select:",
choices = NULL
)
})
shiny::observe({
shinyWidgets::updatePickerInput(
session = getDefaultReactiveDomain(),
inputId = "select",
choices = 1:1000000,
selected = 1
)
})
}
I have a selectizeInput (with parameter multiple = FALSE) in a shiny app. I´m not able to change the multiple-parameter afterwards by using the server-side updateSelectizeInput() and setting the option there.
Here is an example:
library(shiny)
ui <- fluidPage(
selectizeInput(
inputId = "name",
label = "Select Name:",
choices = NULL
)
)
server <- function(input, output, session) {
updateSelectizeInput(
inputId = "name",
choices = c("Markus", "Lisa", "Peter"),
options = list(maxItems = 10),
server = TRUE # set consciously, I have a big list to handle
)
}
shinyApp(ui, server)
If I don´t set the server parameter to TRUE, everything works just fine. Is this a bug or do I miss something?
To select multiple items, you can set multiple=TRUE in the selectizeInput as shown below.
library(shiny)
ui <- fluidPage(
selectizeInput(
inputId = "name",
label = "Select Name:",
choices = NULL, multiple=T
)
)
server <- function(input, output, session) {
updateSelectizeInput(
inputId = "name",
choices = c("Markus", "Lisa", "Peter"),
options = list(maxItems = 10),
server = TRUE # set consciously, I have a big list to handle
)
}
shinyApp(ui, server)
I have written a simple example of what I am doing. I have 3000 numbers that I want to show in a selectInput. The numbers have to be in a reactive function, since in my original work, the data is from a file.
My problem is that when I run the app it only appears 1000 numbers, not the entire data (3000 numbers).
I have seen this post Updating selection of server-side selectize input with >1000 choices fails but I don't know how can I do it using uiOutput and renderUI.
Can anyone help me?
Thanks very much in advance
The code:
library(shiny)
ui <- fluidPage(
titlePanel("Numbers"),
sidebarLayout(
sidebarPanel(
uiOutput('selectUI')
),
mainPanel(
)
)
)
server <- function(input, output) {
num <- reactive({
data = c(1:3000)
return(data)
})
output$selectUI <- renderUI({
selectInput(inputId = 'options', "Select one", choices = num())
})
}
# Run the application
shinyApp(ui = ui, server = server)
Use selectizeInput instead of selectInput with the argument options = list(maxOptions = 3000).
Thanks to Stéphane Laurent's answer, the example will be solved like this:
library(shiny)
ui <- fluidPage(
titlePanel("Numbers"),
sidebarLayout(
sidebarPanel(
selectizeInput(inputId = "options", label = "Select one", choices=character(0)),
),
mainPanel(
)
)
)
server <- function(input, output, session) {
num <- reactive({
data = c(1:3000)
return(data)
})
observe({
updateSelectizeInput(
session = session,
inputId = "options",
label = "Select one",
choices= num(), options=list(maxOptions = length(num())),
server = TRUE)
})
}
# Run the application
shinyApp(ui = ui, server = server)
This code will work if you have more than 3000 entries. It will show you ALL the choices that you have. However, if you have a long list of choices (e.g. 60000) it will decrease the speed of your app.