This is my first question on stackoverflow, and I've been using R for 3 months. I have a lot to learn! Any help is much appreciated. Thank you in advance for your time.
What I WANT to happen: The user selects a category (Animals or Foods) from a drop-down box and clicks Next once. The appropriate ui component will render and display. Then the Next button should be disabled (grayed-out) whenever the right box of the Chooser Input component is empty. Only when the user has at least one selection in the right box, should Next button be enabled and the user may click it.
The PROBLEM: After the Chooser Input component is rendered, the right box is empty, but Next is NOT disabled. Here is the error:
Warning in run(timeoutMs) :
Unhandled error in observer: argument is of length zero
observeEvent(input$widget2)
Below are a demo ui.R and sever.R to recreate my problem. (However, I will be implementing the solution into a larger, more complex GUI.) The code uses shinyBS, so you will first need to install the package and load the library. The code also uses chooserInput, which requires two files: chooser.R and www/chooser-binding.js. See the following link for more information: http://shiny.rstudio.com/gallery/custom-input-control.html
ui
### The following libraries need to be loaded BEFORE runApp()
### library(shiny)
### library(shinyBS)
source("chooser.R") # Used for Custom Input Control UI component (chooserInput)
# chooser.R is saved in the same location as the ui.R and server.R files
# chooserInput also requires chooser-binding JScript script file, which should be located within "www" folder
shinyUI(navbarPage("navbarPage Title",
tabPanel("tabPanel Title", titlePanel("titlePanel Title"),
fluidPage(
#### NEW ROW #####################################################################################################
fluidRow(wellPanel(
# Instructions for initial screen
conditionalPanel(condition = "input.ButtonNext == 0", tags$b("Step 1: Choose category and click 'Next'")),
# Instructions for 'Foods'
conditionalPanel(condition = "input.ButtonNext == 1 && input.widget1 == 'Foods'", tags$b("Step 2: Move Food(s) of interest to the right box and click 'Next'")),
# Instructions for 'Animals'
conditionalPanel(condition = "input.ButtonNext == 1 && input.widget1 == 'Animals'", tags$b("Step 2: Move Animals(s) of interest to the right box and click 'Next'"))
)),
#### NEW ROW #####################################################################################################
fluidRow(
# Drop down box for first selection
conditionalPanel(
condition = "input.ButtonNext == 0",
selectInput("widget1", label = "",
choices = c("Foods",
"Animals"))),
# This outputs the dynamic UI components based on first selection
uiOutput("ui1")
),
#### NEW ROW #####################################################################################################
fluidRow(tags$hr()), # Horizontal line separating input UI from "Next" button
#### NEW ROW #####################################################################################################
fluidRow(
column(1, offset=10,
# UI component for 'Next' button
conditionalPanel(condition = "input.ButtonNext < 2", bsButton("ButtonNext", "Next"))
),
column(1,
HTML("<a class='btn' href='/'>Restart</a>")
)
)
) # End of fluidPage
) # End of tabPanel
)) # End of navbarPage and ShinyUI
server
shinyServer(function(input, output, session) {
# Widget to display when number of clicks of "Next" button (ButtonNext) = 1
output$ui1 <- renderUI({
if(input$ButtonNext[1]==1) {
print("I am in renderUI") # Used to help debug
# Depending on the initial selection, generate a different UI component
switch(input$widget1,
"Foods" = chooserInput("widget2", "Available frobs", "Selected frobs", leftChoices=c("Apple", "Cheese", "Carrot"), rightChoices=c(), size = 5, multiple = TRUE),
"Animals" = chooserInput("widget2", "Available frobs", "Selected frobs", leftChoices=c("Lion", "Tiger", "Bear", "Wolverine"), rightChoices=c(), size = 5, multiple = TRUE)
)
}
}) # End of renderUI
# Disable "Next" button when right side of multi select input is empty
observeEvent(input$widget2, ({
widget2_right <- input$widget2[[2]]
print(widget2_right) # Used to help debug
if(widget2_right == character(0)) {
updateButton(session, "ButtonNext", disabled = TRUE)
} else {
updateButton(session, "ButtonNext", disabled = FALSE)
}
})) # End of observeEvent
}) # End of shinyServer
A similar question (link below) mentioned using Priorities and Resume/Suspend but no example was provided. If that is a valid solution to my problem, please provide some code.
R shiny Observe running Before loading of UI and this causes Null parameters
EXTRA NOTE: The code provided is a small demo recreated from a much larger GUI that I developed for the user to make a series of selections, clicking 'Next' between each selection. Depending on the selections they make each step, new choices are generated from a csv file. Therefore, the ui component that is rendered and displayed is dependent on how many times the user has clicked 'Next' and which selections they've previously made. In the end, the selections are used to sort a large data set so the user can plot only the data they are interested in. The dual conditions are why I used conditionalPanel and the VALUE of the actionButton to render and display the current ui component that the user needs. My code works (except for the problem above - HA!). However, I have read that it is poor coding practice to use the VALUE of an actionButton. If there are any suggestions for another method to handle the dual conditions, please let me know.