Shiny serverside suggestions according to user typing - r

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)

Related

How can I update a subset of values in Shiny once, rather than having it update every time and undoing previous selections?

I want to be able to update my table based on filtering on values within a column, based on a user-provided .csv. The code below works to get my fields populated correctly, but the filtering function is not working correctly, as it re-updates the flow and cancels out any selection I make of a value.
ui <- fluidPage(
fileInput("data", "Load Data", accept = ".csv"),
selectInput("column", "Column", character()),
selectInput("level", "level", "select"),
dataTableOutput("table")
)
server <- function(input, output, session){
options(shiny.maxRequestSize=1000*1024^2)
data <- reactive({
req(input$data)
read.csv(input$data$datapath)
})
observeEvent(data(), {
updateSelectInput(session, "column", choices = names(data()))
})
observeEvent(input$column, {
val <- data()[[input$column]]
updateSelectInput(session, "level", choices = val,
label = paste("Choose level in", input$column))
})
output$table <- renderDataTable({
req(input$level)
filter(data(), input$level == input$level)
})
}
shinyApp(ui = ui, server = server)
I have also tried a dplyr solution for filtering,
filter(input$value == input$value)
but that's not working either, for the same reason. I'm relatively new to Shiny, so any and all assistance and resources are appreciated.
Perhaps you were looking for something like this?
Using the .data pronoun. More information here.
library(shiny)
library(readr)
library(dplyr)
ui <- fluidPage(
fileInput("data", "Load Data", accept = ".csv"),
selectInput("column", "Column", character()),
selectInput("level", "level", "select"),
dataTableOutput("table")
)
server <- function(input, output, session) {
options(shiny.maxRequestSize = 1000 * 1024^2)
data <- reactive({
req(input$data)
read_csv(input$data$datapath)
})
observeEvent(data(), {
updateSelectInput(session, "column", choices = names(data()))
})
observeEvent(input$column, {
val <- data()[[input$column]]
updateSelectInput(session, "level",
choices = unique(val),
label = paste("Choose level in", input$column)
)
})
output$table <- renderDataTable({
req(input$column)
req(input$level)
filter(data(), .data[[input$column]] == input$level)
})
}
shinyApp(ui = ui, server = server)
Tested with iris.csv created with write_csv(iris, "iris.csv")

selectizeInput paramter 'multiple' unchangeable when updated server-side

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)

Update the choices argument of the same radioButtons in shiny

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)

Access input ID of reactive radioButtons in shiny app

I am trying to create a shiny app which includes radioButtons which are reactive to some user input.
I was successful to implement the code from this related question:
Add n reactive radioButtons to shiny app depending on user input
However, in this question it is not described how to access this values.
Here is the example:
server.R
library(shiny)
shinyServer( function(input, output, session) {
output$variables <- renderUI({
numVar <- length(as.integer(input$in0))
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic",x), x,
choices = c("Choice one" = "one",
"Choice two" = "two"), selected = "one"))
})
})
})
ui.R
library(shiny)
shinyUI(pageWithSidebar (
headerPanel("mtcars subset"),
sidebarPanel(
selectInput(inputId = 'in0', label = 'Choose variables',
choices = colnames(mtcars),
multiple = TRUE, selectize = TRUE),
uiOutput("variables")
),
mainPanel()
))
What I have tried so far:
numVar <- length(as.integer(input$in0))
for(i in 1:numVar){
in <- noquote(paste0("dynamic",input$in0[i]))
input$in
}
However, this does not work. Any suggestions?
I'm not sure exactly of your use case but to access the values you could edit your code as below:
numVar <- length(as.integer(input$in0))
for(i in 1:numVar){
value <- paste0("dynamic",input$in0[i])
input[[value]]
}
Basically you need to use input[[value]] as opposed to input$value in this case. It doesn't seem that R allows you to use in as a variable (probably because it's already used in other contexts). You don't need noquote() anymore.
Welcome to stackoverflow!
You were almost there. However, you'll have to make sure, that you are accessing the inputs in a reactive context.
Here is a working example:
library(shiny)
ui <- fluidPage(
pageWithSidebar (
headerPanel("mtcars subset"),
sidebarPanel(
selectInput(inputId = 'in0', label = 'Choose variables',
choices = colnames(mtcars),
multiple = TRUE, selectize = TRUE),
uiOutput("variables")
),
mainPanel(
textOutput("myChoicesDisplay")
)
)
)
server <- function(input, output, session) {
output$variables <- renderUI({
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic", x), x,
choices = c("Choice one" = "one",
"Choice two" = "two"), selected = "one"))
})
})
myChoices <- reactive({
dynInputList <- list()
for(dynInputs in paste0("dynamic", input$in0)){
dynInputList[[dynInputs]] <- input[[dynInputs]]
}
return(dynInputList)
})
output$myChoicesDisplay <- renderText({
paste(input$in0, myChoices(), sep = ": ", collapse = ", ")
})
}
shinyApp(ui, server)

R shiny favourites in long selectInput lists

How do I deal with long lists of options? In the example below, I have a subset of the options as favourites, but want to be able to select all options including the non-favourites. How do I get the input$selected to return what I selected last based on both the radiogroupbutton() and the selectInput()?
EDIT: I would like to keep the look, which has radiobuttons AND a drop down list. Therefore, I assume both will need different inputID's which then could be combined (somehow) in the server site (as Joris suggested). I am not sure how to combine them on the server site, and how to identify what was selected last.
ALL.options <- apply(expand.grid(LETTERS, LETTERS), 1, function(x){paste(x, collapse="")})
favourites <- sample(ALL.options, 20)
ui <- fluidPage(
h3("Favourites:"),
radioGroupButtons(inputId="selected",
choices = sort(favourites),
individual = TRUE,
selected = NULL,
width="20%"),
selectInput(inputId="selected", label = "Other options",
choices = ALL.options,
selected = NULL),
h3("THIS IS YOUR SELECTION:"),
verbatimTextOutput("choice")
)
)
server <- function(input, output) {
output$choice <- renderPrint(
input$selected
)
}
shinyApp(ui, server)
Perhaps it suffices to use a single selectInput or selectizeInput that lists the Favourites and Other options in separate option groups (see e.g. Shiny: Option groups for selectize input):
library(shiny)
ALL.options <- apply(expand.grid(LETTERS, LETTERS), 1, function(x){paste(x, collapse="")})
favourites <- sample(ALL.options, 20)
ui <- fluidPage(
selectizeInput(inputId = "selected", label = "All options", choices = list(
Favourites = favourites,
`Other options` = setdiff(ALL.options, favourites)
),
options = list(
placeholder = '<None selected>',
onInitialize = I('function() { this.setValue(""); }')
)
),
h3("THIS IS YOUR SELECTION:"),
verbatimTextOutput("choice")
)
server <- function(input, output) {
output$choice <- renderPrint({
validate(need(input$selected, "None selected"))
input$selected
})
}
shinyApp(ui, server)
NB: If you instead use two separate inputs (radioGroupButtons and selectInput) you could combine the selected choices server-side in a reactive object. For instance:
library(shiny)
library(shinyWidgets)
ALL.options <- apply(expand.grid(LETTERS, LETTERS), 1, function(x){paste(x, collapse="")})
favourites <- sample(ALL.options, 20)
ui <- fluidPage(
h3("Favourites:"),
radioGroupButtons(inputId = "radio",
choices = sort(favourites),
individual = TRUE,
selected = character(0),
width="20%"),
selectizeInput(inputId="select", label = "Other options",
choices = ALL.options,
options = list(
placeholder = '<None selected>',
onInitialize = I('function() { this.setValue(""); }')
)
),
h3("THIS IS YOUR SELECTION:"),
verbatimTextOutput("choice")
)
server <- function(input, output) {
## initialize reactive value
currentSelected <- reactiveVal(NULL)
## update based on radioGroupButtons
observeEvent(input$radio, {
currentSelected(input$radio)
})
## update based on selectInput
observeEvent(input$select, {
currentSelected(input$select)
})
output$choice <- renderPrint({
validate(need(currentSelected(), "None selected"))
currentSelected()
})
}
shinyApp(ui, server)
Created on 2019-06-17 by the reprex package (v0.3.0)
I am not sure if I understand fully what you are trying to achieve. I also notice that both the radioGroupButtons and the selectInput have the same inputId. If the idea is to print both the choices, you could change the inputId of the selectInput to say, select and just modify the renderPrint as:
output$choice <- renderPrint(
c(input$selected, input$select)
)
Is this what you are looking for?

Resources