How to branch processing using picker input - r

I am currently developing a Shiny app.
I would like to use multiple Picker Inputs to branch the processing flow.
Specifically, I would like to build the processing flow shown in the figure below.
For example
When Option1 is selected in PickerInput1
→ PickerInput2 displays the vector of Middle Class.
→ Set the Multiple option of PickerInput2 to False to make it a single selection.
→ Turn off Numeric Input so that you cannot enter numbers.
(Make it gray out or hide it on the UI in the first place)
→ Press the button to display "expression1".
When Option2 is selected in PickerInput1
→ PickerInput2 displays the vector of Middle Class.
→ Set the Multiple option of PickerInput2 to False to make it a single selection.
→ Turn on Numeric Input so that you cannot enter numbers.
→ Press the button to display "expression1".
When Option3 is selected in PickerInput1
→ PickerInput2 displays the vector of Middle Class and Major Class.
→ Set the Multiple option of PickerInput2 to True to select multiple options.
→ Turn off Numeric Input so that you cannot enter numbers.
→ Press the button to display "expression2".
When Option4 is selected in PickerInput1
→ PickerInput2 displays the MajorClass vector.
→ Set the Multiple option of PickerInput2 to True to select multiple options.
→ Turn off Numeric Input so that you cannot enter numbers.
→ Press the button to display "expression2".
Is it possible to branch the processing flow in this way?
I especially want to hear
・ Is it possible to change the Mutiple settings?
(Maybe I will use updatePickerInput, but can I change it with that function?)
・ Can Numeric Input be switched ON / OFF?
The sample code is below.
library("shiny")
library("shinyWidgets")
major_class <- c("A1","A2","A3")
middle_class <- c("A1_1","A1_2","A2_1","A2_2","A3_1","A3_2")
ui <- fluidPage(
fluidRow(
column(
width = 2, offset = 1,
pickerInput(
inputId = "p1",
label = "PickerInput1",
choices = c("Option1","Option2","Option3","Option4"),
options = list(
`live-Search` = TRUE,
`actions-box` = TRUE,
size = 7,
`selected-text-format` = "count > 3"
),
multiple =FALSE
)
),
column(
width = 2,
pickerInput(
inputId = "p2",
label = "PickerInput2",
choices = "",
options = list(
`live-Search` = TRUE,
`actions-box` = TRUE,
size = 7,
`selected-text-format` = "count > 3"
),
multiple =TRUE
),
numericInput("num", label = "Numeric input", value = 1)
),
column(
width = 2,
actionButton("p3","finish")
),
textOutput("resule_message")
)
)
server <- function(input, output, session) {
observeEvent(input$p1 ,{
if(input$p1 %in% c("Option1","Option2")){
updatePickerInput(session = session, inputId = "p2",
choices = middle_class)
}
if(input$p1 %in% c("Option3")){
updatePickerInput(session = session, inputId = "p2",
choices = list(major = major_class,
middle = middle_class))
}
if(input$p1 %in% c("Option4")){
updatePickerInput(session = session, inputId = "p2",
choices = major_class)
}
})
observeEvent(input$p3 ,{
if(input$p1 %in% c("Option1")){
output$resule_message <- renderText({
paste0("expression1")
})
}
else{
output$resule_message <- renderText({
paste0("expression2")
})
}
})
}
shinyApp(ui = ui, server = server)
Those who can solve this problem, those who know how to change the processing flow depending on the input conditions of PikcerInput,
If you know that you can do something similar using another method, please let me know.

One way to do it is to use renderUI for your second pickerInput and display it based on your conditions. Try this
library("shiny")
library("shinyWidgets")
major_class <- c("A1","A2","A3")
middle_class <- c("A1_1","A1_2","A2_1","A2_2","A3_1","A3_2")
ui <- fluidPage(
fluidRow(
column(
width = 2, offset = 1,
pickerInput(
inputId = "p1",
label = "PickerInput1",
choices = c("Option1","Option2","Option3","Option4"),
options = list(
`live-Search` = TRUE,
`actions-box` = TRUE,
size = 7,
`selected-text-format` = "count > 3"
),
multiple =FALSE
)
),
column(
width = 2, uiOutput("pickr2"), uiOutput("numinput")
),
column(
width = 2,
actionButton("p3","finish")
),
textOutput("resule_message")
)
)
server <- function(input, output, session) {
output$pickr2 <- renderUI({
req(input$p1)
if(input$p1 %in% c("Option1","Option2")){
choices <- middle_class
TORF <- FALSE
}else{
TORF <- TRUE
if(input$p1 %in% c("Option3")){
choices <- c(middle_class,major_class)
}else choices <- major_class
}
pickerInput(
inputId = "p2",
label = "PickerInput2",
choices = choices,
options = list(
`live-Search` = TRUE,
`actions-box` = TRUE,
size = 7,
`selected-text-format` = "count > 3"
),
multiple =TORF
)
})
output$numinput <- renderUI({
req(input$p1)
if(input$p1 %in% c("Option2")){
numericInput("num", label = "Numeric input", value = 1)
}else return(NULL)
})
observeEvent(input$p3 ,{
req(input$p1)
if(input$p1 %in% c("Option1")){
output$resule_message <- renderText({
paste0("expression1")
})
}else{
output$resule_message <- renderText({
paste0("expression2")
})
}
})
}
shinyApp(ui = ui, server = server)

Related

swap pickerInput on a button press in Shiny

I need to update/reverse two inputs from drop down inputs upon a button press. At the moment when I hit the swap button (reverse_xz), it reacts however the updatePickerInput doesn't switch my x and z inputs.
I wanted to have the functionality where, once the swap button is clicked, switch the already selected pickerInputs. Then, all the drop down choices (including the selected) need to get reversed. The reason we have to remove the selected choices from vector is to prevent duplicate selections in both x and z inputs.
I am not sure if I have to render the pickerInput ui on the server side?!
This is my code below:
#global.R
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
library(shinyjs)
#variable labels
my_vars <- c("None"= "NONE",
"All" = "all_all",
"Pro" = "Pro_",
"Locomania" = "locomania_Type",
"Racer" = "race")
#ui.R
ui <- shinydashboardPlus::dashboardPage(
header = shinydashboardPlus::dashboardHeader( ),
body = shinydashboard::dashboardBody( box(textOutput("inputs") ) ),
sidebar = shinydashboardPlus::dashboardSidebar(
shinyWidgets::pickerInput(
inputId = "xvar",
label = "X Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "all_all"
),
# Button to reverse the choices
shiny::fluidRow(
shiny::column(12, offset = 4,
shinyWidgets::actionBttn(
inputId = "reverse_xz",
label = "",
style = "simple",
color = "primary",
icon = icon("retweet")
)
)
),
shinyWidgets::pickerInput(
inputId = "zvar",
label = "Z Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "race"
)
)
)
#server.R
server <- function(input, output, session) {
#
observe({
if(!is.null(input$reverse_xz))
shinyWidgets::updatePickerInput(session, "zvar",
choices = my_vars[!(my_vars %in% input$xvar)],
selected = isolate(input$zvar) )
shinyWidgets::updatePickerInput(session, "xvar",
choices = my_vars[!(my_vars %in% input$zvar)],
selected = isolate(input$xvar) )
})
# These observers remove the selected choices so both pickers are unique
observe({
if(!is.null(input$zvar))
shinyWidgets::updatePickerInput(session, "xvar",
choices = my_vars[!(my_vars %in% input$zvar)],
selected = isolate(input$xvar) )
})
observe({
if(!is.null(input$xvar))
shinyWidgets::updatePickerInput(session, "zvar",
choices = my_vars[!(my_vars %in% input$xvar)],
selected = isolate(input$zvar) )
})
# output inputs
output$inputs <- renderText({ paste0("x var: ", input$xvar,
"\n\n\n z var:", input$zvar,
"\n\n\nreverse press: ", input$reverse_xz) })
}
shiny::shinyApp(ui= ui, server= server)
Thank you in advance. I have looked at some relavant posts however they couldn't guide me much:
Updatepickerinput with change in pickerinput in Shiny
updatePickerInput not updating values after changing tabs in R shiny
update pickerInput by using updatePickerInput in shiny
Look at this and check if it would be OK for you:
#global.R
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
library(shinyjs)
#variable labels
my_vars <- c("None"= "NONE",
"All" = "all_all",
"Pro" = "Pro_",
"Locomania" = "locomania_Type",
"Racer" = "race")
#ui.R
ui <- shinydashboardPlus::dashboardPage(
header = shinydashboardPlus::dashboardHeader( ),
body = shinydashboard::dashboardBody( box(textOutput("inputs") ) ),
sidebar = shinydashboardPlus::dashboardSidebar(
shinyWidgets::pickerInput(
inputId = "xvar",
label = "X Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "all_all"
),
# Button to reverse the choices
shiny::fluidRow(
shiny::column(12, offset = 4,
shinyWidgets::actionBttn(
inputId = "reverse_xz",
label = "",
style = "simple",
color = "primary",
icon = icon("retweet")
)
)
),
shinyWidgets::pickerInput(
inputId = "zvar",
label = "Z Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "race"
)
)
)
#server.R
server <- function(input, output, session) {
#
observeEvent(input$reverse_xz, {
shinyWidgets::updatePickerInput(session, "zvar",
choices = my_vars[!(my_vars %in% input$zvar)],
selected = input$xvar)
shinyWidgets::updatePickerInput(session, "xvar",
choices = my_vars[!(my_vars %in% input$xvar)],
selected = input$zvar)
})
observe({
if (input$xvar == input$zvar && (length(input$zvar) > 0 && length(input$xvar) > 0)) {
shinyWidgets::updatePickerInput(session, "zvar",
selected = "")
shinyWidgets::updatePickerInput(session, "xvar",
selected = "")
}
})
# output inputs
output$inputs <- renderText({ paste0("x var: ", input$xvar,
"\n\n\n z var:", input$zvar,
"\n\n\nreverse press: ", input$reverse_xz) })
}
shiny::shinyApp(ui= ui, server= server)
I think that maybe this needs an explanation:
if (input$xvar == input$zvar && (length(input$zvar) > 0 && length(input$xvar) > 0))
So, when user choose two the same inputs, then we are updating pickerInputs, so both will have "Nothing selected" as a sign for user that something goes wrong (or that she/he did something wrong). However, "Nothing selected" is like NULL and we can't use NULL like this NULL == "something" inside if, so I'm checking if some input is NULL using length(input$) > 0, because length of NULL is 0. Instead of length(input$) > 0 you could use !is.null(input$) and maybe you should as it is probably more readable, but I'm leaving this decision for you.

In R Shiny, how to write a function that generates additional user inputs upon clicking an action button?

I'm working on an App that allows the user to optionally expand a base starting input (firstInput in the below MWE). SecondInput allows the user to vertically expand his assumptions (doesn't work in this MWE but in full App it runs extrapolations and interpolations, and it expands vertically fitting well in a sidebar panel). ThirdInput below is neutered for illustration simplicity. FourthInput, appearing in modalDialog, allows user to expand assumptions horizontally. The inputs are sequentially chained (firstInput -> secondInput -> fourthInput) with the last input taking precedence. Chaining works fine.
In full App I have vertical expansion working. Now I need help with horizontal assumption expansion.
As shown in the image at the bottom, in the modalDialog, how can I have a click of the "Add scenario" actionButton add another input matrix to the right, called "fifthInput"? Another click would add "sixthInput" to the right, etc. This is what I mean by "horizontal expansion". As far as chaining, these new inputs matrices would be chained to secondInput just like fourthInput is. A click of the "Remove above" actionButton would remove the input matrix immediately above it. I'm not sure how large a modalDialog box expands but I may need some kind of box that allows vertical/horizontal scrolling. If this is a bit much, I wonder if there's some sort of package that does or helps with this.
MWE code:
library(shiny)
library(shinyjs)
library(shinyMatrix)
f <- function(action,i){as.character(checkboxInput(paste0(action,i),label=NULL))}
actions <- c("show", "reset")
tbl <- t(outer(actions, c(1,2), FUN = Vectorize(f)))
colnames(tbl) <- c("Show", "Reset")
rownames(tbl) <- c("2nd input", "3rd input")
firstInput <- function(inputId){
matrixInput(inputId,
value = matrix(c(5), 1, 1, dimnames = list(c("1st input"),NULL)),
rows = list(extend = FALSE, names = TRUE),
cols = list(extend = FALSE, names = FALSE, editableNames = FALSE),
class = "numeric")}
secondInput <- function(inputId,x){
matrixInput(inputId,
value = matrix(c(x), 1, 1, dimnames = list(c("2nd input"),NULL)),
rows = list(extend = FALSE, names = TRUE),
cols = list(extend = FALSE, names = FALSE, editableNames = FALSE),
class = "numeric")}
fourthInput <- function(inputId,x){
matrixInput(inputId,
value = matrix(c(x), 1, 1, dimnames = list(c("4th input"),NULL)),
rows = list(extend = FALSE, names = TRUE),
cols = list(extend = FALSE, names = FALSE, editableNames = FALSE),
class = "numeric")}
ui <- fluidPage(
tags$head(
tags$style(HTML(
"td .checkbox {margin-top: 0; margin-bottom: 0;}
td .form-group {margin-bottom: 0;}"
))
),
br(),
sidebarLayout(
sidebarPanel(
uiOutput("panel"),
hidden(uiOutput("secondInput")),
actionButton("showFourth","Show 4th input (in modal)",width = "100%") # ADDED
),
mainPanel(plotOutput("plot1"))
)
)
server <- function(input, output){
input1 <- reactive(input$input1)
input2 <- reactive(input$input2)
input4 <- reactive(input$input4)
output$panel <- renderUI({
tagList(
useShinyjs(),
firstInput("input1"),
strong(helpText("Generate curves (Y|X):")),
tableOutput("checkboxes")
)
})
output[["checkboxes"]] <-
renderTable({tbl},
rownames = TRUE, align = "c",
sanitize.text.function = function(x) x
)
observeEvent(input[["show1"]], {
if(input[["show1"]]){shinyjs::show("secondInput")} else
{shinyjs::hide("secondInput")}
})
observeEvent(input$showFourth,{
showModal(
modalDialog(
column(4,
actionButton("add","Add scenario"), div(style = "margin-bottom: 10px"),
fourthInput("input4",if(isTruthy(input$input4)){input$input4} else {input$input2[1,1]}),
actionButton("remove","Remove above")
),
footer = modalButton("Close")
)) # close showModal and modalDialog
})
output$secondInput <- renderUI({
req(input1())
secondInput("input2",input$input1[1,1])
})
outputOptions(output,"secondInput",suspendWhenHidden = FALSE)
output$plot1 <-renderPlot({
req(input2())
plot(rep(if(isTruthy(input$input4)){input4()} else {input2()}, times=5))
})
}
shinyApp(ui, server)
I always underestimate package shinyMatrix, turns out it has the horizontal extension feature I'm looking for and extensions can be grouped in 2's as I need. See modified MWE code reflecting this usage of shinyMatrix for extensions. Basically for the column specifications for matrixInput (in custom function fourthInput), all I did was add extend = TRUE, delta = 2, delete = TRUE, .... Extend means the matrix can be expanded (column-wise since this is in the column parameters section), delta of 2 = matrix expands in grouping of 2, delete = columns can be deleted.
However shinyMatrix output isn't the prettiest thing out there, I'm open to other solutions or packages!!
MWE code:
library(shiny)
library(shinyjs)
f <- function(action,i){as.character(checkboxInput(paste0(action,i),label=NULL))}
actions <- c("show", "reset")
tbl <- t(outer(actions, c(1,2), FUN = Vectorize(f)))
colnames(tbl) <- c("Show", "Reset")
rownames(tbl) <- c("2nd input", "3rd input")
xDflt <- 10
yDflt <- 5
userInput <- function(inputId,x,y,z){
matrixInput(inputId,
value = matrix(c(x,y), 1, 2, dimnames = list(c(z),c("X and Y",""))),
rows = list(extend = FALSE, names = TRUE),
cols = list(
extend = FALSE,
names = TRUE,
editableNames = FALSE,
multiheader=TRUE
),
class = "numeric")}
fourthInput <- function(inputId,x,y,z){
matrixInput(inputId,
value = matrix(c(x,y), 1, 2, dimnames = list(c(z),c("X and Y",""))),
label = "Add, delete, or modify matrix parameters:",
rows = list(extend = FALSE, names = TRUE),
cols = list(
extend = TRUE,
delta = 2,
delete = TRUE,
names = TRUE,
editableNames = FALSE,
multiheader=TRUE
),
class = "numeric")}
ui <- fluidPage(
tags$head(
tags$style(HTML(
"td .checkbox {margin-top: 0; margin-bottom: 0;}
td .form-group {margin-bottom: 0;}"
))
),
br(),
sidebarLayout(
sidebarPanel(
uiOutput("panel"),
hidden(uiOutput("secondInput")),
actionButton("showFourth","Show 4th input (in modal)",width = "100%")
),
mainPanel(plotOutput("plot1"))
)
)
server <- function(input, output){
input1 <- reactive(input$input1)
input2 <- reactive(input$input2)
input4 <- reactive(input$input4)
output$panel <- renderUI({
tagList(
useShinyjs(),
userInput("input1",xDflt,yDflt,"1st input"),
strong(helpText("Generate curves (Y|X):")),
tableOutput("checkboxes")
)
})
output[["checkboxes"]] <-
renderTable({tbl},
rownames = TRUE, align = "c",
sanitize.text.function = function(x) x
)
observeEvent(input[["show1"]], {
if(input[["show1"]]){shinyjs::show("secondInput")} else
{shinyjs::hide("secondInput")}
})
observeEvent(input$showFourth,{
showModal(
modalDialog(
fourthInput("input4",
xDflt,
if(isTruthy(input$input4)){input$input4[1,2]} else
{input$input2[1,2]},
"4th input"),
footer = modalButton("Close")
))
})
output$secondInput <- renderUI({
req(input1())
userInput("input2",xDflt,input$input1[1,2],"2nd Input")
})
outputOptions(output,"secondInput",suspendWhenHidden = FALSE)
output$plot1 <-renderPlot({
req(input2())
plot(rep(if(isTruthy(input$input4)){input4()[1,2]} else {input2()[1,2]}, times=10))
})
}
shinyApp(ui, server)

how to control the values entered in selectizeInput in Shiny, making sure they belong to a predifined list?

I would like that when user exits the selectizeInput field (clicks outside of selectizeInput), a new option is created and selected (option createOnBlur = TRUE), but I can't figure out how to control the created values to ensure they belong to the "choices" list.
In fact, I would like createOnBlur=TRUE working with create=FALSE, but this obviously doesn't work..
I have looked at selectize.js documentation and I think createFilter and/or onBlur() options could be useful but I didn't succeed in implementing it for my purpose.
Here is a reprex with an age input, I would like that when user tape e.g. "40" and then clik outside of input without pressing "Enter" (ie onBlur), the value 40 is recorded in the input, but if the user tape e.g "444", this impossible age value is not created in the list of choices :
library(shiny)
input_age <- function(mina = 0, maxa =100){
selectizeInput(inputId = "age",
label = "Age",
choices = c("choose one" = "", mina:maxa),
options = list(create = TRUE,
createOnBlur = TRUE)
)
}
ui <- shinyUI(fluidPage(
titlePanel("selectize createonblur"),
mainPanel(
input_age(mina = 20, maxa = 70)
)
))
# SERVER
server <- shinyServer(function(input, output) {
})
shinyApp(ui, server)
You can use updateSelectizeInput to check the selection made against the choices after each interaction with your input.
Please see the following:
library(shiny)
input_age <- function(mina = 0, maxa = 100){
selectizeInput(inputId = "age",
label = "Age",
choices = c("choose one" = "", mina:maxa),
options = list(create = TRUE,
createOnBlur = TRUE)
)
}
minAge <- 20
maxAge <- 70
ui <- shinyUI(fluidPage(
titlePanel("selectize createonblur"),
mainPanel(
input_age(mina = minAge, maxa = maxAge)
)
))
# SERVER
server <- shinyServer(function(input, output, session) {
observeEvent(req(input$age), {
if(length(setdiff(input$age, as.character(seq(minAge, maxAge)))) > 0){
updateSelectizeInput(session,
inputId = "age",
choices = seq(minAge, maxAge),
selected = "")
}
})
})
shinyApp(ui, server)
Update - Here is a JS approach:
library(shiny)
input_age <- function(mina = 0, maxa = 100){
selectizeInput(inputId = "age",
label = "Age",
choices = c("choose one" = "", mina:maxa),
options = list(create = TRUE,
createOnBlur = TRUE))
}
ui <- shinyUI(fluidPage(
tags$head(tags$script(HTML("
$(document).on('shiny:inputchanged', function(event) {
if (event.name === 'age') {
if (isNaN(parseInt(event.value)) || event.value > 70 || event.value < 20) {
var $select = $('#age').selectize();
var selectize = $select[0].selectize;
selectize.setValue(null, true);
}
}
});
"))),
titlePanel("selectize createonblur"),
mainPanel(
input_age(mina = 20, maxa = 70)
)
))
# SERVER
server <- shinyServer(function(input, output, session) {
})
shinyApp(ui, server)
You can supply a regular expression to the createFilter option. If the user types something which doesn't match this regular expression, then "Add ..." will not appear and it will not be possible to add this item.
library(shiny)
ui <- fluidPage(
titlePanel("selectize createonblur"),
mainPanel(
selectizeInput(
inputId = "age",
label = "Age",
choices = c("choose one" = "", 20:70),
options = list(
create = TRUE,
createOnBlur = TRUE,
createFilter = I("/^([2-6][0-9]|70)$/")
)
)
)
)
server <- function(input, output, session) {}
shinyApp(ui, server)

Rshiny conditional button/divs/table if button is pressed or rows selected from DT

I can use conditionals in the UI for input fields without involving the server side. But when I try to do it for things like input_rows_selected or the state of a button; they don't work.
Below I have a couple of input fields set up with conditionals. The 2nd field depends on something in the first being selected. Then the first button depends on something in the second field being selected.
This is where it goes wrong. The third button is supposed to only show up if rows are selected in the datatable. I have gotten it working if ONE row is selected, but not more than one row. And then the html and table below the third button is only supposed to be displayed once the third button is pressed. Currently the html is displayed, and the table doesn't work.
Ideas? I am hoping to keep it as much as possible in the UI side. That way I can easily adapt the button hide/display functionality to various other chunks of code. But I'm not sure if that's possible.
EDIT: UPDATED TO CURRENT CODE
EDIT 2: UPDATED TO FINAL WORKING CODE
if (interactive()) {
library(shiny)
items <- data.frame(
category = c("Room", "IceBreaker", "Activity", "Break"),
group = c(1, 2, 3, 4),
className = c ("red_point", "blue_point", "green_point", "purple_point"),
content = c("Big Room", "Introductions", "Red Rover", "Lunch"),
length = c(480, 60, 120, 90)
)
ui <- fluidPage(shinyUI(
tagList(
useShinyalert(),
useShinyjs(),
title = "Conditional Inputs",
tabsetPanel(id = "mainTabset",
tabPanel(
title = "Wheeeeeee!",
class = "inputs",
column(
12,
selectInput(
inputId = "input1",
label = "A, B, or C?",
choices = c(
Choose = '',
A = 'a',
B = 'b',
C = 'c'
),
selectize = FALSE
),
conditionalPanel(
condition = "input.input1 !== ''",
selectInput(
inputId = "input2",
label = "D, or E?",
choices = c(Choose = '',
D = 'd',
E = 'e'),
selectize = FALSE
)
),
conditionalPanel(
condition = "input.input2 !== ''",
actionButton(
"button1",
"SUBMIT",
style = "background-color:#221B70;
color:#E0EB15;
border-color:#E61029;
border-style:double;
border-width:4px;
border-radius:50%;
font-size:19px;"
),
DT::dataTableOutput("tbl1"),
conditionalPanel(
condition = "typeof input.tbl1_rows_selected !== 'undefined' && input.tbl1_rows_selected.length > 0",
actionButton(
"button2",
"GENERATE TABLE",
style = "background-color:#221B70;
color:#E0EB15;
border-color:#E61029;
border-style:double;
border-width:4px;
border-radius:50%;
font-size:19px;"
)
),
conditionalPanel(condition = "input.button2 > 0",
div(
"Selected items:", DT::dataTableOutput("tbl2")
))
)
)
))
)
))
server <- function(input, output) {
observeEvent(input$button1, {
output$tbl1 <- DT::renderDataTable({
items
}, selection = 'multiple',
class = "display nowrap compact",
extensions = 'Scroller',
options = list(dom = 'Bfrtip'))
})
observeEvent(input$button2, {
table <- items[input$tbl1_rows_selected,c(2,3,4)]
output$tbl2 <- DT::renderDataTable({
table
})
})
}
shinyApp(ui, server)
}
input$tbl1_rows_selected is a single integer if only one row is selected, it is a vector if several rows are selected, and it is NULL if no row is selected. So the appropriate condition is
"input.tbl1_rows_selected !== null"
input$button2 is always an integer. It is initialized to 0 and then it increments each time the button is pressed. The condition to check that the button has been pressed is then
"input.button2 > 0"
I don't see what you mean by "the table below the third button". I don't see any table below this button.
EDIT
That does not work:
"input.tbl1_rows_selected !== null"
That works:
"input.tbl1_rows_selected.length > 0"
It seems that input.tbl1_rows_selected is an empty JavaScript array when input$tbl1_rows_selected is NULL in R. Otherwise it is a non-empty array

updateCheckBoxGroupInput in shiny based on selection of other checkboxes

My shiny application has multiple tabs. In one of the tabs I have plot output which I want to use to create reports in another tab. I have included a checkbox in the first tab for the user to select the output for reporting. In the second tab I am trying to update a check box group input based on the selection of the first tab. However I am getting only the first option selected.
The reproducible code is as follows: This is based on ifelse condition:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
title = "MODULE",titleWidth = 225
),
dashboardSidebar(
width = 225,
sidebarMenu(id = "tabs",
menuItem("TOPLINES", tabName = "tplines", icon = shiny::icon("dashboard")),
menuItem("MY MONTHLY REPORTS", tabName = "myweeklyrep", icon = shiny::icon("compass"))
)),
dashboardBody(
tabItems(
tabItem(
tabName = "tplines",
fluidRow(
box(
checkboxInput(inputId = "inventorytop8metrocheck", "Add to reports", value = FALSE),
width = 6, status = "info", title = "Inventory information",
div(plotlyOutput("inventorytop8metro"), width = "100%", height = "400px", style = "font-size:80%;")
),
box(
checkboxInput(inputId = "top15categoriestplinescheck", "Add to reports", value = FALSE),
width = 6, status = "info", title = "Top 15 categories",
div(plotlyOutput("top15categoriestplines"), style = "font-size:90%")
))),
tabItem(
tabName = "myweeklyrep",
fluidRow(
h4("AVAILABLE ANALYSIS", align = 'center'),br(),
column(width = 12,
list(tags$div(align = 'left',
class = 'multicol',
checkboxGroupInput(inputId = 'analysisSelector',
label = "Select the analysis:",
choices = "",
selected = "",
inline = FALSE)))
))))))
server <- function(session,input,output){
observe({
updateCheckboxGroupInput(session, inputId = "analysisSelector", label = "", choices =
ifelse(!is.null(input$top15categoriestplinescheck) || length(input$top15categoriestplinescheck) != 0, "Inventory top 8 metros",
ifelse(!is.null(input$inventorytop8metrocheck) || length(input$inventorytop8metrocheck) != 0, "Top 15 categories - Topline", "No selection")),
selected = "",inline = FALSE)
})
}
shinyApp(ui,server)
I tried with if, else if also but they aren't working. Any thoughts?
The if, else if conditions:
updateCheckboxGroupInput(session, inputId = "analysisSelector", label = "", choices =
if(!is.null(input$top15categoriestplinescheck) || length(input$top15categoriestplinescheck) != 0){
"Inventory top 8 metros"
} else if (!is.null(input$inventorytop8metrocheck) || length(input$inventorytop8metrocheck) != 0){
"Top 15 categories - Topline"
} else {
return()
},
selected = "",inline = FALSE)
EDIT:
I tried the following option: which renders the checkboxes irrespective of whether they are selected or not.
getlist <- reactive({
if(!is.null(input$top15categoriestplinescheck) & !is.null(input$inventorytop8metrocheck)){
c("Top 15 categories - Topline","Inventory of top 8 metros - Topline")
} else if (!is.null(input$top15categoriestplinescheck)){
"ABC"
} else if (!is.null(input$inventorytop8metrocheck)){
"DEF"
} else {
return()
}
})
observe({
updateCheckboxGroupInput(session, inputId = "analysisSelector", label = "Select the analysis:", choices =
as.list(getlist()),
selected = "",inline = FALSE)
})
This is actually easier to handle with observeEvent as explained in the documentation of this function (see ?observeEvent). From what I understand, it actually wraps observe but in a more intuitive way.
You have to pass it two arguments: an event (in this case, the click on one of your checkboxGroupInputs) and the action to perform when this event occurs.
The server function thus becomes:
server <- function(session,input,output){
updateAnalysisSelector <- function(session) {
choices <- ifelse(input$top15categoriestplinescheck, "Inventory top 8 metros",
ifelse(input$inventorytop8metrocheck, "Top 15 categories - Topline", "No selection"))
updateCheckboxGroupInput(session,
inputId = "analysisSelector",
label = "Select the analysis:",
choices = choices,
selected = "",
inline = FALSE)
}
observeEvent(input$top15categoriestplinescheck, updateAnalysisSelector(session))
observeEvent(input$inventorytop8metrocheck, updateAnalysisSelector(session))
}
I'm sure this could be simplified if your UI did not have two separate checkbox groups but this works for your current implementation.

Resources