I have a rather complex logic for updating 4 interdependent selectizeInputs().
I spotted the huge difference in the behaviour after a Chrome update few weeks ago where selectize.js with large number of choices simply crashes.
So far so good, I knew about shiny's server-side option so I gave it a try and since that moment a cry :D
The whole dependency chain for my selectizeInputs broke and I have spent few days to isolate the problem.
Apparently, in client side mode after a field is updated with updateSelectizeInput() the new value is immediately inserted in the UI and dependent observers are triggered once.
In server-side mode this happens in two steps where the selectizeInput is first cleared and then the new value is inserted.
The problem is that this way all dependencies of a certain field are triggered once with empty "" value and once after that with the correct value.
Between these 2 triggers all dependencies manage to mess up their own values a lot.
Please refer to the code and output below.
In serverMode = FALSE in Server Mode = TRUE
1. Start the app
2. choose category "B" or "C"
3. write "apple" in Item and click "Add.. apple"
serverMode = FALSE # assign TRUE to see the difference
library(shiny)
# Define UI for application that draws a histogram
ui <- shinyUI(fluidPage(
# Application title
titlePanel("Selectize Server-Side VS Cliend-Side Mode"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
radioButtons(
inputId = "cat"
, label = "Category"
, choices = list("A", "B", "C")
, selected = "A"
, inline = TRUE
, width = NULL
)
, selectizeInput(
inputId = "item"
, label = "Items"
, choices = list()
, options = list(
maxOptions = 10
, placeholder = 'Choose ...'
, preload = TRUE
, create = TRUE
, server = serverMode
)
)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
# Define server logic required to draw a histogram
server <- shinyServer(function(input, output, session) {
item_select_cat <- eventReactive(
c(
does_item_exists()
),{
print("item_select_cat ...")
if(does_item_exists()) query_item_cat()
else NULL
}, ignoreNULL = TRUE
)
observeEvent(
item_select_cat()
,{
print("UPDATE_CAT_FROM_ITEM...")
updateRadioButtons(
session = session
,inputId = 'cat'
,selected = item_select_cat()
)
print("UPDATE_CAT DONE!")
}
)
#########################################################
################# Self update chain #####################
#########################################################
is_item_in_choices <- eventReactive(
c(
input$item
)
,{
print(c("Item value is : ", input$item))
print("is_item_in_choices...")
if(input$item %in% query_item_choices() || input$item == "") NULL#FALSE # ||
else FALSE
}
)
query_item_cat <- eventReactive(
is_item_in_choices()
,{
print("query_item_cat...")
query$item_cat(input$item)
}
)
does_item_exists <- eventReactive(
query_item_cat()
,{
print("does_item_exists...")
if(is.null(query_item_cat())) FALSE
else TRUE
}, ignoreNULL = FALSE
)
self_update_item <- observeEvent(
{
does_item_exists()
},{
print("SELF UPDATE ITEM...")
if(!does_item_exists()){
print("ITEM DOES NOT Exists!")
updateSelectizeInput(
session = session
,inputId = 'item'
,choices = query_item_choices()
,selected = 0
,server = serverMode
)
}
print(c("ITEM after self update is: ", input$item))
}
)
#########################################################
################### UP update chain #####################
#########################################################
query_item_choices <- eventReactive(
c(
input$cat
),{
print("query_item_choices...")
query$item(input$cat)
}
)
cat_update_item <- observeEvent(
{
query_item_choices()
},{
print("CAT UPDATE ITEM...")
updateSelectizeInput(
session = session
,inputId = 'item'
,choices = query_item_choices()
,selected = input$item
,server = serverMode
)
}
)
})
query <- list()
query$item_cat <- function(item = character()){
switch (item
, "apple" = "A"
, "pear" = "A"
, "banana" = "A"
, "tomato" = "B"
, "pepper" = "B"
, "onion" = "B"
, "milk" = "C"
, "juice" = "C"
, "water" = "C"
)
}
query$item <- function(cat = character()){
switch (cat
,"A" = c("apple", "pear", "banana")
,"B" = c("tomato", "pepper", "onion")
,"C" = c("milk", "juice", "water")
)
}
# Run the application
shinyApp(ui = ui, server = server)