My Shiny Algorithm (app.R code at the bottom):
What I did in the code: Used IF condition for "None" and "Country"; used Switch for "State" and "City".
My Problem: Everything is working as expected except one: If we select "State" after selecting "None", I am seeing both textOutput and State filter instead of country and state filters. This happens because the IF statement in "None" or "Country", unlike switch(), just prints the UI and wouldn't clear the UI if another selection is made
My Constraint:
Country filter input need to be duplicated in the code ("State" should give both country and state filters, similarly for "City") but we cannot duplicate inputs with same ID in shiny code
I cannot use different country filter IDs to provide the same input because I need the input values in country filter to be read in multiple places and I would need to duplicate all those and that would complicate everything
Where I need help: My only issue here is, I need both "Country" and ("State"/"City") filter to appear if a user selects ("State"/"City") after "None" (bypassing "Country"!!!).
Really need this thing to get fixed. Any help would be appreciated
Thanks!
Dummy Data: https://docs.google.com/spreadsheets/d/1E9dbtOMm1-7ZjIHu3Ra_NyFBHrCQdITG2_xuMIMKDOs/edit?usp=sharing
app.R code
library(shiny)
ui <- fluidPage(
fileInput("file_attr", "Door attributes:"),
selectInput("select", label = "Region Drop down", choices = list("None", "Country", "State","City"), selected = "None"),
uiOutput("NoneCountryFilter"),
uiOutput("StateCityFilter")
)
server <- function(input, output, session) {
#Reading input
data_attr <- reactive({
file1 <- input$file_attr
if(is.null(file1)){return()}
read.table(file=file1$datapath, sep=",", header = TRUE, stringsAsFactors = FALSE)
})
#Filter interactivity
#Reading Lists
countries <- reactive({
if(is.null(data_attr()$Country)){return()}
data_attr()$Country
})
states <- reactive({
if(is.null(data_attr()$State)){return()}
data_attr()$State[data_attr()$Country %in% input$show_vars]
})
cities <- reactive({
if(is.null(data_attr()$City)){return()}
data_attr()$City[data_attr()$Country %in% input$show_vars]
})
#Filters based on Region Drop down
observeEvent(input$file_attr,{
observe({
if ("None" %in% input$select){
output$NoneCountryFilter <- renderUI({
if(is.null(data_attr()$Country)){return()}
h4("No region Selected")
})
}
if ("Country" %in% input$select){
output$NoneCountryFilter <- renderUI({
if(is.null(data_attr()$Country)){return()}
selectizeInput('show_vars', 'Country Filter', choices = c("Select All","None", unique(countries())), multiple = TRUE)
})
}
})
output$StateCityFilter <- renderUI({
switch(input$select,
"State" = (
selectizeInput('show_vars_state', 'State Filter', choices = c("Select All","None", unique(states())), multiple = TRUE)
),
"City" = (
selectizeInput('show_vars_city', 'City Filter', choices = c("Select All","None", unique(cities())), multiple = TRUE)
)
)
})
})
#Giving "Select ALL" and "None" Functionality to each filter (This part is redundant for the current problem. I am keeping this so that I could check any solution from stackoverflow should not effect other functionalities)
#Countries- SelectAll & None
observe({
if ("Select All" %in% input$show_vars){
selected_choices <- setdiff(c("Select All",unique(countries())), "Select All")
updateSelectizeInput(session, 'show_vars', choices = c("Select All","None",unique(countries())), selected = selected_choices)
}
})
observe({
if ("None" %in% input$show_vars){
updateSelectizeInput(session, 'show_vars', choices = c("Select All", "None", unique(countries())),selected = "")
}
})
#State- SelectAll & None
observe({
if ("Select All" %in% input$show_vars_state){
selected_choices <- setdiff(c("Select All",unique(states())), "Select All")
updateSelectizeInput(session, 'show_vars_state', choices = c("Select All","None",unique(states())), selected = selected_choices)
}
})
observe({
if ("None" %in% input$show_vars_state){
updateSelectizeInput(session, 'show_vars_state', choices = c("Select All", "None", unique(states())),selected = "")
}
})
#City- SelectAll & None
observe({
if ("Select All" %in% input$show_vars_city){
selected_choices <- setdiff(c("Select All",unique(cities())), "Select All")
updateSelectizeInput(session, 'show_vars_city', choices = c("Select All", "None", unique(cities())), selected = selected_choices)
}
})
observe({
if ("None" %in% input$show_vars_city){
updateSelectizeInput(session, 'show_vars_city', choices = c("Select All", "None", unique(cities())),selected = "")
}
})
}
shinyApp(ui = ui, server = server)
You could use conditionalPanel
to determine which elements to be displayed based on certain conditions.
Notes:
I used req()
in data_attr
as this is checks for file_attr
. You don't have to use is.null()
.
I used three conditionalPanel
for Country, State, City, and specified the conditions for each one.
Inside the condition, input.select
is used not input$select
.
library(shiny)
ui <- fluidPage(
fileInput("file_attr", "Door attributes:"),
selectInput("select", label = "Region Drop down",
choices = list("None", "Country", "State","City"), selected = "None"),
# Selectize Inputs ---------------
uiOutput("Country_List"),
uiOutput("State_List"),
uiOutput("City_List")
)
server <- function(input, output, session) {
#Reading input
data_attr <- reactive({
req(input$file_attr) # make sure a file was uploaded
read.table(file=input$file_attr$datapath, sep=",", header = TRUE, stringsAsFactors = FALSE)
})
# Country selectizeInput ----------------------
output$Country_List <- renderUI({
conditionalPanel(
condition = "input.select == 'Country' | input.select == 'State'| input.select == 'City' ",
selectizeInput('show_var', 'Country Filter',
choices = c("Select All","None", unique(data_attr()$Country)), multiple = TRUE)
)
})
# State selectizeInput ----------------------
output$State_List <- renderUI({
conditionalPanel(
condition = "input.select == 'State' ",
selectizeInput('show_vars_state', 'State Filter',
choices = c("Select All","None", unique(data_attr()$State)), multiple = TRUE)
)
})
# City selectizeInput -----------------------
output$City_List <- renderUI({
conditionalPanel(
condition = "input.select == 'City' ",
selectizeInput('show_vars_city', 'City Filter',
choices = c("Select All","None", unique(data_attr()$City)), multiple = TRUE)
)
})
}
shinyApp(ui = ui, server = server)