In my Shiny app, I want to include a selectInput in a DT datatable and allow selection of multiple options. This renders fine with multiple = F, but with multiple = T, the selection doesn't display or work properly. Please see example below. When "Multiple" is unselected, the selectInput renders fine in the table, but when it is selected, the selectInput is not rendered properly. Any suggestions?
Update: I modified the code to include a selectInput by itself with multiple = TRUE to show what I expect it to look like in the table. Specifically, in the table, there is no field above the dropdown with the selections displayed and I am unable to select multiple choices. Also see screenshot.
require(shiny)
require(DT)
shinyApp(
ui = fluidPage(
checkboxInput(inputId = "multiple", label = "Multiple", value = F),
selectInput(inputId = "expected", label = "Expected", choices = letters, multiple = T),
DT::dataTableOutput("mytable")
),
server = function(input, output, session) {
output$mytable <- DT::renderDataTable({
if(is.null(input$multiple)) return()
DT::datatable(
data = data.frame(
Col1 = c(
as.character(selectInput(
inputId = "id1",
label = NULL,
choices = letters,
multiple = input$multiple
))
)
),
escape = F,
selection = "none"
)
})
}
)
Update 2:
Thanks to #Jamie for a great solution. I was able to modify that solution when I need multiple selectInputs in my table and want the same desired format. See below:
require(shiny)
require(DT)
SelectizeIDs <- function(ids) {
myStrings <- as.character(sapply(ids, function(id) {
paste0(" $('#", id, "').selectize();")
}))
c(
"function(settings){",
myStrings,
"}"
)
}
shinyApp(
ui = fluidPage(
checkboxInput(inputId = "multiple", label = "Multiple", value = F),
selectInput(inputId = "expected", label = "Expected", choices = letters, multiple = T),
DT::dataTableOutput("mytable")
),
server = function(input, output, session) {
output$mytable <- DT::renderDataTable({
DT::datatable(
data = data.frame(
Col1 = c(
as.character(selectInput(
inputId = "id1",
label = NULL,
choices = letters,
multiple = input$multiple
)),
as.character(selectInput(
inputId = "id2",
label = NULL,
choices = letters,
multiple = input$multiple
))
)
),
escape = F,
selection = "none",
options = list(
ordering = F,
initComplete = JS(SelectizeIDs(c("id1", "id2"))),
preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
)
)
})
}
)
Here's an option where I leaned heavily from this question.
SelectizeInput inside DT::datatable only works as html
Which leans on this question. Shiny widgets in DT Table
Since your data data.frame has the appropriate html already set up. You need to make sure that selectize is added to the id in this case id1. From inspecting element on your expected vs actual input, it looks like all the selectize JS is being excluded
js <- c(
"function(settings){",
" $('#id1').selectize()",
"}"
)
Then in the options initialize the js function above and and bind the inputs.
shinyApp(
ui = fluidPage(
checkboxInput(inputId = "multiple", label = "Multiple", value = F),
selectInput(inputId = "expected", label = "Expected", choices = letters, multiple = T),
DT::dataTableOutput("mytable")
),
server = function(input, output, session) {
output$mytable <- DT::renderDataTable({
# if(is.null(input$multiple)) return()
DT::datatable(
data = data.frame(
Col1 = c(
as.character(selectInput(
inputId = "id1",
label = NULL,
choices = letters,
multiple = input$multiple
))
)
),
escape = F,
selection = "none",
options = list(
initComplete = JS(js),
preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
)
)
})
}
)
Related
I have 4 dependent selection fields realized with selectizeGroup functions. I would like to limit the number of choices to only one item in each field. Is it possible?
The code below works like a charm for multiple selections in each field. I would like to limit the selections so only picking one is possible. Where and what parameter to add if it exists?
Here is my working selectizeGroup application:
ui <- fluidPage(
fluidRow(
column(
width = 10, offset = 1,
tags$h3("Filter data with selectize group"),
panel(
selectizeGroupUI(
id = "my-filters",
inline = TRUE,
params = list(
p_lev5 = list(
inputId = "p_lev5",
title = "Level 5",
placeholder = 'select',
options = list(limit = 1)
),
p_min = list(
inputId = "p_min",
title = "Group minor",
placeholder = 'select'
),
sm = list(
inputId = "sm",
title = "Manager",
placeholder = 'select'
),
rp = list(
inputId = "rp",
title = "Representative",
placeholder = 'select'
)
),
),
status = "primary"
),
plotOutput("plot1")
)
)
)
server = function(input, output, session) {
res_mod <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = df_prc_ch_minor,
vars = c("p_lev5", "p_min", "sm", "rp")
)
output$plot1 <-
renderPlot({
req( input[["my-filters-p_lev5"]],
input[["my-filters-p_min"]],
input[["my-filters-sm"]],
input[["my-filters-rp"]])
fn_plt_prcech(
input[["my-filters-p_lev5"]],
input[["my-filters-p_min"]],
input[["my-filters-sm"]],
input[["my-filters-rp"]])
})
}
shinyApp(ui, server)
The part options = list(limit = 1) is what I dream about, of course. Thank you for all the indications.
BACKGROUND:
I have a large list of stock symbols, 27,000 rows, that I would like to be choices in a selectizeInput() on a shinyApp. Since the list is large I am using server = T in updateSelectizeInput().
AIM:
I would like the options list to not load/render until a user starts typing a string into selectizeInput(), so that I can return all symbols that start with that letter, to reduce loading all 27,000 rows in the input. I would like input$ticker to be what is observed and then what triggers the filtering code logic. How can i achieve this without using a specific button?
Shown below is
intended output, but with a button to produce the behavior instead of the user being in the text box. This is along the lines of what I would like, but does not automatically start searchign when I type in the box and has bad code smell to me.
current logic, using input$ticker in an observer to trigger selection of df and populate updateSelectize() with new choices, but is failing and the app is evaluating too soon?\
trying to load choices once, using upload button only doesn't work
REPREX:
1.
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- {
renderUI(
shiny::fluidRow(
bs4Dash::box(
title = shiny::selectizeInput(
inputId = "ticker",
label = "Ticker:",
choices = NULL,
selected = "AAPL",
options = list(
placeholder = "e.g AAPL",
create = TRUE,
maxOptions = 50L
)
),
actionButton(
inputId = "update",
label = "UPDATE NOW"
),
id = "tickerBox",
closable = F,
maximizable = F,
width = 12,
height = "250px",
solidHeader = FALSE,
collapsible = F
)
)
)
}
server <- function(input, output, session){
choice <- reactive(
tickers[startsWith(tickers$symbol, input$ticker), ]
)
observeEvent(input$update, {
updateSelectizeInput(
session = session,
label = "Ticker:",
inputId ="ticker",
choices = choice(),
server = TRUE
)
})
}
shiny::shinyApp(ui = ui, server = server)
# REPREX for selectize, glitches and `input$ticker` observer causes loop gltich?
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- {
renderUI(
shiny::fluidRow(
bs4Dash::box(
title = shiny::selectizeInput(
inputId = "ticker",
label = "Ticker:",
choices = NULL,
selected = "AAPL",
options = list(
placeholder = "e.g AAPL",
create = TRUE,
maxOptions = 50L
)
),
actionButton(
inputId = "update",
label = "UPDATE NOW"
),
id = "tickerBox",
closable = F,
maximizable = F,
width = 12,
height = "250px",
solidHeader = FALSE,
collapsible = F
)
)
)
}
server <- function(input, output, session){
# updateSelectizeInput(
# session = session,
# label = "Ticker:",
# inputId ="ticker",
# choices = tickers,
# server = TRUE
# )
observeEvent(input$ticker, {
choices <- tickers[startsWith(tickers$symbol, input$ticker), ]
updateSelectizeInput(
session = session,
label = "Ticker:",
inputId ="ticker",
choices = choices,
server = TRUE
)
})
}
shiny::shinyApp(ui = ui, server = server)
# REPREX for selectize
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- {
renderUI(
shiny::fluidRow(
bs4Dash::box(
title = shiny::selectizeInput(
inputId = "ticker",
label = "Ticker:",
choices = NULL,
selected = "AAPL",
options = list(
placeholder = "e.g AAPL",
create = TRUE,
maxOptions = 50L
)
),
actionButton(
inputId = "update",
label = "UPDATE NOW"
),
id = "tickerBox",
closable = F,
maximizable = F,
width = 12,
height = "250px",
solidHeader = FALSE,
collapsible = F
)
)
)
}
server <- function(input, output, session){
# One call to try and load ticker df
observeEvent(input$update, {
updateSelectizeInput(
session = session,
label = "Ticker:",
inputId ="ticker",
choices = ticker,
server = TRUE
)
})
}
shiny::shinyApp(ui = ui, server = server)
SEE SIMILAR POSTS:
SO POST 1, SO POST 2, SO POST 3
What do you think about something like this?
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- fluidPage(
tags$head(
tags$script(
HTML(
'document.addEventListener("keydown", function(e) {
Shiny.setInputValue("key_pressed", e.key);
})'
)
)
),
fluidRow(
column(2, selectizeInput("select", "Select", choices = "")),
column(1, actionButton("btn", "Search"))
)
)
server <- function(input, output, session) {
observeEvent(input$btn, {
req(input$key_pressed)
updateSelectizeInput(session, "select", choices = tickers[startsWith(tickers, input$key_pressed)], server = TRUE)
})
}
shinyApp(ui, server)
Basically I think it is not possible to just use the words which are putted to the selectInput and we need separate input. I think that selectInput is truthy (isTruthy()) only after some option was chosen (and it can't be "" of course), so we can't use anything which is putted as a word to the selectInput box before some option is actually chosen. I'm not sure, but if I'm right, it is necessary to have separate input for what you want.
However, if we could assume that:
User will use only one letter to get the options to choose
Then we can use "keydown" event (keydown). Now the user doesn't need to put anything to the selectInput box, she/he can just use a key in the keyboards, like C (letter size does matter here, because we are using startsWith()) and then push "Search" button (but of course this letter can still be put to the selectInput box to mimic what you tried to achieve). We could even imagine solution without the button, but I'm afraid in most use-cases it will be not recommended, I mean if user can interact with the app using keyboard not only to choose the options, but also for other purposes, then we would recompute new options everytime user uses key in the keyboard for - well - nothing.
Turns out that selectizeInput doesn't accept a df and must be an atomic vector. When I used tickers[[1]], the issue seemed to be solved, and the list would no longer flash.
I am creating an app where you can select the columns that you want to see/show and do the logarithm or sqrt to the entire dataframe. The first option (selection) is running through pickerInput and the second with checkboxInputs.
In order to show the table with your selection or your changes in the dataframe, you have to click an actionButton. The selection of the columns works perfectly but if you click one of the checkboxInput after your selection, the selection is removed and you will see all the columns again.
This is how it looks when you want to do the logarithm after your selection. The selection of the columns disappear.
This is the code:
library(shiny)
library(shinyWidgets)
library(dplyr)
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
uiOutput("picker"),
checkboxInput("play", strong("I want to play with my data"), value = FALSE),
conditionalPanel(
condition = "input.play == 1",
checkboxInput("change_log2", "Log2 transformation", value = FALSE),
checkboxInput("run_sqrt", "sqrt option", value = FALSE)),
actionButton("view", "View Selection")
),
# Show a plot of the generated distribution
mainPanel(
h2('Mydata'),
DT::dataTableOutput("table"),
)
)
)
library(shiny)
library(DT)
server <- function(session, input, output) {
data <- reactive({
mtcars
})
data1 <- reactive({
dat <- data()
if(input$change_log2){
dat <- log2(dat)
}
if(input$run_sqrt){
dat <- sqrt(dat)
}
dat
})
observeEvent(input$play, {
if(!input$play) {
updateCheckboxInput(session, "change_log2", value = FALSE)
updateCheckboxInput(session, "run_sqrt", value = FALSE)
}
})
output$picker <- renderUI({
pickerInput(inputId = 'pick',
label = 'Choose',
choices = colnames(data1()),
options = list(`actions-box` = TRUE),
multiple = T,
selected = colnames(data1())
)
})
datasetInput <- eventReactive(input$view,{
datasetInput <- data1() %>%
select(input$pick)
return(datasetInput)
})
output$table <- renderDT({
datatable(
datasetInput(),
filter="top",
rownames = FALSE,
extensions = 'Buttons',
options = list(
dom = 'Blfrtip',
buttons =
list('copy', 'print', list(
extend = 'collection',
buttons = list(
list(extend = 'csv', filename = "File", title = NULL),
list(extend = 'excel', filename = "File", title = NULL)),
text = 'Download'
))
),
class = "display"
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Does anyone know what I should do to fix this?
Thanks very much in advance
Regards
That is because your pickerInput is based on data1(), and that changes based on the checkbox selection. In fact, it should be using data(). Try this
output$picker <- renderUI({
pickerInput(inputId = 'pick',
label = 'Choose',
choices = colnames(data()),
options = list(`actions-box` = TRUE),
multiple = T,
selected = colnames(data())
)
})
I am trying to make a dynamic UI for my shiny dashboard. Here, I want to show a pickerInput field only when the input in a checkboxGroup is a specific value. For example, when the input from the checkboxGroup field is A, I want to show the pickerInput field, otherwise I want to show a different input field.
Currently, the part of my code looks, using conditionalPanel, like the following:
output$UI_selection <- renderUI({
tagList(
p(tags$i("Define the network")),
checkboxGroupInput(inputId = "choice1",
label = "Make a choice",
choices = list("A", "B")
),
conditionalPanel(condition = "input$choice1 == 'A'",
pickerInput(inputId = "select1",
label = "Select first:",
choices = list(
"Hierarchies" = grouplist_1),
selected = NULL,
options = list(`actions-box` = TRUE, `none-selected-text` = "Select hierarchy", `live-search` = TRUE, title = "Select hierarchy"),
multiple = FALSE
)
)
)
})
However, this doesn't work and shows both the checkboxGroupInput as well as the PickerInput. Does anyone know how to fix this?
The shiny package functions (such as conditionalPanel) translate all of the R language code you supply into JS. Conditions you supply in conditionalPanel need to be interpretable in JS, which uses . in place of $.
You need to replace your condition = "input$choice1 == 'A'" with condition = "input.choice1 == 'A'".
Full working app is here:
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
uiOutput("UI_selection")
)
server <- function(input, output, session) {
output$UI_selection <- renderUI({
tagList(
p(tags$i("Define the network")),
checkboxGroupInput(inputId = "choice1",
label = "Make a choice",
choices = list("A", "B")
),
conditionalPanel(condition = "input.choice1 == 'A'",
pickerInput(inputId = "select1",
label = "Select first:",
choices = list(
"Hierarchies" = c("X","Y","Z")),
selected = NULL,
options = list(`actions-box` = TRUE, `none-selected-text` = "Select hierarchy", `live-search` = TRUE, title = "Select hierarchy"),
multiple = FALSE
)
)
)
})
}
shinyApp(ui, server)
I have solved this programmed but while changing input I am unable to find output change as a table please any one can help me using R shiny code
I have solve the error but it's still showing only
library(shiny)
library(DT)
bcl <- read.csv("R-D.csv", stringsAsFactors = FALSE)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("TYPE.OF.DATA","View data by:", choices = c("NP", "CR", "AN"), inline = TRUE, selected = "NP"),
tags$hr(),
radioButtons(" LINE.OF.BUSINESS ","View data by:" ,choices = c("AF", "HL"), inline = TRUE, selected = "AF"),
tags$hr(),
selectInput("typeInput6", " APPLICATION ",
choices = c("TERADATA"),
selected = "TERADATA"),
tags$hr(),
radioButtons( "DatabaseName","View data by:",choices = c("DW_re", "DW_np", "DW_AN"), inline = TRUE, selected = "DW_re")
),
mainPanel(
DT::dataTableOutput("table")
)
)
))
server <- shinyServer(function(input, output,session) {
observe({
if(input$bcl == "TYPE.OF.DATA"){
choices = c("NP", "CR", "AN")
firstchoice = "NP"
label = "DATA TYPE:"
}else{
choices = c("DW_re", "DW_np", "DW_AN")
firstchoice = "DW_re"
label = "NAME:"
}
updateSelectInput(session, "bcl", label = label, choices = choices, selected = firstchoice)
})
data <- reactive({
data = switch(input$bcl,
"NP" = NP, "CR" = CR, "AN" = AN,
"DW_re" = DW_re, "DW_np" = DW_np, "DW_AN" = DW_AN
)
})
output$table <- DT::renderDataTable({
datatable(data())
})
})
shinyApp(ui=ui,server=server)