selectizeInput difference in server-side and client-side mode reactions?

436 views
Skip to first unread message

Aleksandar Kittov

unread,
Jul 29, 2016, 10:25:42 AM7/29/16
to Shiny - Web Framework for R
Hi all,

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] "Item value is : " "apple"           
[1] "is_item_in_choices..."
[1] "query_item_cat..."
[1] "does_item_exists..."
[1] "item_select_cat ..."
[1] "UPDATE_CAT_FROM_ITEM..."                                 
[1] "UPDATE_CAT DONE!"
[1] "SELF UPDATE ITEM..."
[1] "ITEM after self update is: " "apple"                      
[1] "query_item_choices..."
[1] "CAT UPDATE ITEM..."                                         ###### as in client mode plus ######
                                                                                  [1] "Item value is : " ""                
                                                                                  [1] "is_item_in_choices..."
                                                                                  [1] "Item value is : " "apple"           
                                                                                  [1] "is_item_in_choices..."

Test procedure: 
1. Start the app
2. choose category "B" or "C"
3. write "apple" in Item and click "Add.. apple"

Any suggestion or advise is highly appreciated :)

Cheers,
Aleks


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)

Aleksandar Kittov

unread,
Aug 4, 2016, 7:43:24 AM8/4/16
to Shiny - Web Framework for R
I have been researching more, trying to find the reason for this double invalidation of selectize in server-mod, and found out this:

  # session$onFlushed is necessary to work around a bug in the Shiny/Leaflet
  # integration; without it, the addCircle commands arrive in the browser
  # before the map is created.
  session$onFlushed(once=TRUE, function() {


I have tried to use it in my case but it seems I cannot make it work. 

Is it me who is not doing it correctly or that is not the related at all?

Thanks

Aleks
Reply all
Reply to author
Forward
0 new messages