updateSelectizeInput in a shiny module
Asked Answered
S

2

5

I would like to use a reactive value to load control a selectizeInput widget. I can do this with a simple shiny app, but I can't seem to be able to replicate it when I try to reorganize it in a module.

In the following code I have a simple app with an input widget and a button. After pressing the button, I want the selectizeInput() widget to be updated with the values stored in the reactive variable.

library(shiny)

# GLOBAL VAR TO BE LOADED after pressing the button
# -------------
STORED <- reactiveValues(choices = c("a", "b", "c")
                         , selected = c("c"))

# UI
# -------------
ui <- fixedPage(
  wellPanel(
    # input widget
    selectInput("widget1"
                , "label"
                ,choices = c("WRONG A","WRONG B","WRONG C")
                ,selected="WRONG A"
                )

    # update button
    , actionButton("plotBtn"
                   , "update"
                   , class = "btn-primary")
  )
)

# SERVER
# -------------
server <- function(input, output, session) {

  observeEvent(input$plotBtn,{
    message("update button was pressed")

    updateSelectInput(session
                      ,"widget1"
                      ,choices = STORED$choices
                      , selected = STORED$selected
    )
  })
}

# APP
shinyApp(ui, server)

after pressing the button, the widget is correctly updated with "c" selected, and the choices are correctly imported. However, when I try to write it as a shiny module, the button doesn't work.

library(shiny)

# INIT VARS TO BE LOADED AFTER PRESSING THE BUTTON
# ------------------------------------------------------------------------------
STORED <- reactiveValues(choices = c("a", "b", "c")
                         , selected = c("c"))

# MODULE SELECTIZEINPUT
# ------------------------------------------------------------------------------
input_widgetUI <- function(id) {
  ns <- NS(id)

  selectizeInput(ns("input_widget")
                 , label = "label"
                 , choices = c("WRONG A","WRONG B","WRONG C")
                 , selected = "WRONG A"
  )

}

# MODULE BUTTON
# ------------------------------------------------------------------------------
plotBtnUI <- function(id){

  ns <- NS(id)

  fluidPage(actionButton(ns("plotBtn"), "update", class = "btn-primary"))
}

plotBtn <- function(input, output, session) {

  ns <- session$ns

  print("Loading plotBtn()")

  observeEvent(input$plotBtn, {

    message("update button was pressed")

    updateSelectizeInput(session
                         , ns("widget1")
                         , choices = STORED$choices
                         , selected= STORED$selected
                         )

  })
}


# #############################################################################
# SHINY APP
# #############################################################################
ui <- fixedPage(
  wellPanel(
    input_widgetUI("widget1")
    , plotBtnUI("button")
  )
)

server <- function(input, output, session) {
  callModule(plotBtn, "button")
}


shinyApp(ui, server)

I belive I might be using the wrong ID. Any suggestion is very welcome! Thanks

Selfexpression answered 28/11, 2017 at 11:11 Comment(2)
Why are you using modules? Can't you just put everything inside server / uiRashid
Modules can be very hekpful at times, especially when you are working with many idsUncontrollable
S
2

This solution is closer to what I was looking for. It still allows to keep the button and the input widget in distinct modules (i.e. have the button on a different tab for example).

library(shiny)
options(shiny.reactlog=TRUE)

# INIT GLOBAL VARS
# --------------------------------------------------------------------
STORED <- reactiveValues(choices = c("WRONG A","WRONG B","WRONG C")
                         , selected = "WRONG A")

# MODULE SELECTIZEINPUT
#----------------------------------------------------------------------
input_widgetUI <- function(id) {

  ns <- NS(id)

  tagList(
    selectizeInput(ns("input_widget")
                   , label = "label"
                   , choices = NULL
                   , selected = NULL
    )
  )
}

input_widgetSERVER <- function(input, output, session){

  #ns <- session$ns

  observe({

    updateSelectizeInput(session
                        , "input_widget"
                        , choices = STORED$choices
                        , selected= STORED$selected
                        , server=TRUE
                        )
  })

}

# MODULE BUTTON
# ---------------------------------------------------------------------
plotBtnUI <- function(id){

  ns <- NS(id)

  fluidPage(actionButton(ns("plotBtn"), "update", class = "btn-primary"))
}

plotBtnSERVER <- function(input, output, session) {

   #ns <- session$ns

   print("Loading plotBtn()")

   observeEvent(input$plotBtn, {

     message("update button was pressed")

     # VARS TO BE LOADED AFTER PRESSING THE BUTTON
     STORED$choices <- c("a", "b", "c")
     STORED$selected <- c("c")

   })
}


# ######################################################################
# SHINY APP
# ######################################################################
ui <- fixedPage(
  tagList(
      input_widgetUI("widget1")
    , plotBtnUI("button")
  )
)

server <- function(input, output, session) {
  callModule(input_widgetSERVER, "widget1")
  callModule(plotBtnSERVER, "button")
}
# launch the app
shinyApp(ui, server)
Selfexpression answered 29/11, 2017 at 16:35 Comment(0)
U
4

you want to have the selectizeInput and actionButton in the same UI function. otherwise will you have different namespaces for each of them. In this case you also don't need the ns function in the server part. You only need that when you are rendering dynamic UI objects

Here is working version of your code

STORED <- reactiveValues(choices = c("a", "b", "c")
                         , selected = c("c"))

# MODULE SELECTIZEINPUT
# ------------------------------------------------------------------------------
input_widgetUI <- function(id) {
  ns <- NS(id)
  tagList(
  selectizeInput(ns("input_widget")
                 , label = "label"
                 , choices = c("WRONG A","WRONG B","WRONG C")
                 , selected = "WRONG A"
  ),
  actionButton(ns("plotBtn"), "update", class = "btn-primary")  
  )

}


plotBtn <- function(input, output, session) {

  ns <- session$ns

  print("Loading plotBtn()")

  observeEvent(input$plotBtn, {

    message("update button was pressed")
    updateSelectizeInput(session = getDefaultReactiveDomain()
                         , inputId = "input_widget"
                         , choices = STORED$choices
                         , selected= STORED$selected
    )

  })
}


# #############################################################################
# SHINY APP
# #############################################################################
ui <- fixedPage(
  wellPanel(
    input_widgetUI("widget1")
  )
)
server <- function(input, output, session) {
  callModule(plotBtn, "widget1")
}
shinyApp(ui, server)
Uncontrollable answered 28/11, 2017 at 15:30 Comment(1)
Thanks for your suggestion!Selfexpression
S
2

This solution is closer to what I was looking for. It still allows to keep the button and the input widget in distinct modules (i.e. have the button on a different tab for example).

library(shiny)
options(shiny.reactlog=TRUE)

# INIT GLOBAL VARS
# --------------------------------------------------------------------
STORED <- reactiveValues(choices = c("WRONG A","WRONG B","WRONG C")
                         , selected = "WRONG A")

# MODULE SELECTIZEINPUT
#----------------------------------------------------------------------
input_widgetUI <- function(id) {

  ns <- NS(id)

  tagList(
    selectizeInput(ns("input_widget")
                   , label = "label"
                   , choices = NULL
                   , selected = NULL
    )
  )
}

input_widgetSERVER <- function(input, output, session){

  #ns <- session$ns

  observe({

    updateSelectizeInput(session
                        , "input_widget"
                        , choices = STORED$choices
                        , selected= STORED$selected
                        , server=TRUE
                        )
  })

}

# MODULE BUTTON
# ---------------------------------------------------------------------
plotBtnUI <- function(id){

  ns <- NS(id)

  fluidPage(actionButton(ns("plotBtn"), "update", class = "btn-primary"))
}

plotBtnSERVER <- function(input, output, session) {

   #ns <- session$ns

   print("Loading plotBtn()")

   observeEvent(input$plotBtn, {

     message("update button was pressed")

     # VARS TO BE LOADED AFTER PRESSING THE BUTTON
     STORED$choices <- c("a", "b", "c")
     STORED$selected <- c("c")

   })
}


# ######################################################################
# SHINY APP
# ######################################################################
ui <- fixedPage(
  tagList(
      input_widgetUI("widget1")
    , plotBtnUI("button")
  )
)

server <- function(input, output, session) {
  callModule(input_widgetSERVER, "widget1")
  callModule(plotBtnSERVER, "button")
}
# launch the app
shinyApp(ui, server)
Selfexpression answered 29/11, 2017 at 16:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.