0

In a Shiny app, I’m trying to disable/enable an action button in the UI of the main app based on user's input from a module. Basically, I want the “Next Page” (submit) button to be disabled until the user responds to the last item (item3). When the user responds to the last item, I want the button to be enabled. However, my app isn’t updating the toggle state of the action button.

Here’s a minimal reproducible example using a {Golem} structure:

app_ui.R:

library("shiny")
library("shinyjs")

app_ui <- function(request) {
  tagList(
    useShinyjs(),
    fluidPage(
      mod_mod1_ui("mod1_ui_1"),
      actionButton(inputId = "submit",
                   label = "Next Page")
    )
  )
}

app_server.R:

library("shiny")
library("shinyjs")

app_server <- function( input, output, session ) {
  state <- mod_mod1_server("mod1_ui_1")
  
  # Enable the "Next Page" button when the user responds to the last item
  observe({
    toggleState("submit", state == TRUE)
    })  
}

mod_mod1.R:

library("shiny")
library("shinyjs")

mod_mod1_ui <- function(id){
  ns <- NS(id)
  tagList(
    radioButtons(inputId = ns("item1"),
                 label = "Item 1",
                 choices = c(1, 2, 3, 4),
                 selected = character(0)),
    
    radioButtons(inputId = ns("item2"),
                 label = "Item 2",
                 choices = c(1, 2, 3, 4),
                 selected = character(0)),
    
    radioButtons(inputId = ns("item3"),
                 label = "Item 3",
                 choices = c(1, 2, 3, 4),
                 selected = character(0))
  )
}

mod_mod1_server <- function(id){
  moduleServer( id, function(input, output, session){
    ns <- session$ns
    
    # When the user completes the last survey question
    completed <- logical(1)
    
    observe({
      lastQuestion <- input$item3
      if(!is.null(lastQuestion)){
        completed <- TRUE
      } else {
        completed <- FALSE
      }
      browser()
    })
    
    return(completed)
 
  })
}

Using browser() statements, it appears that the completed variable is correctly being updated in the module, but that the state variable isn’t updating in the main app.

itpetersen
  • 1,269
  • 3
  • 11
  • 30

1 Answers1

1

I am not clear if you want this to work when the user responds to only item3 or all items (1 thru 3). I am assuming that it is the latter. However, you can modify as your use case requires it. Defining a reactiveValues object works. Try this

library("shiny")
library("js")

mod_mod1_ui <- function(id){
  ns <- NS(id)
  tagList(
    radioButtons(inputId = ns("item1"),
                 label = "Item 1",
                 choices = c(1, 2, 3, 4),
                 selected = character(0)),
    
    radioButtons(inputId = ns("item2"),
                 label = "Item 2",
                 choices = c(1, 2, 3, 4),
                 selected = character(0)),
    
    radioButtons(inputId = ns("item3"),
                 label = "Item 3",
                 choices = c(1, 2, 3, 4),
                 selected = character(0))
  )
}

mod_mod1_server <- function(id){
  moduleServer( id, function(input, output, session){
    ns <- session$ns
    
    # When the last survey question is completed
    rv <- reactiveValues(completed=1)
    
    observe({
      lastQuestion <- input$item3
      if(!is.null(lastQuestion) & !is.null(input$item2) & !is.null(input$item1)){
        rv$completed <- 1
      } else {
        rv$completed <- 0
      }
      print(rv$completed )
      #browser()
      
    })
    
    return(rv)
  })
}

app_ui <- function(request) {
  fluidPage(
    useShinyjs(),
    tagList(
      mod_mod1_ui("mod1_ui_1"),
      actionButton(inputId = "submit",
                   label = "Next Page") 
    )
  )
}

app_server <- function( input, output, session ) {
  state <- mod_mod1_server("mod1_ui_1")
  
  # Don't show "Next Page" button until last item is completed
  observe({
    toggleState("submit", state$completed == TRUE)
  })
 
}

shinyApp(ui = app_ui, server = app_server)
YBS
  • 8,571
  • 2
  • 4
  • 16